Contributing
Contributing to Sublarr
Section titled “Contributing to Sublarr”Thank you for your interest in contributing to Sublarr! This document provides guidelines and instructions for contributing to the project.
Table of Contents
Section titled “Table of Contents”- Getting Started
- Development Setup
- Code Style Guidelines
- Testing
- Pull Request Process
- Reporting Issues
- Adding New Features
- License
Getting Started
Section titled “Getting Started”Sublarr is a standalone subtitle manager and translator built with:
- Backend: Python 3.11, Flask, SQLite
- Frontend: React 18, TypeScript, Tailwind CSS
- Deployment: Docker
Before contributing, please:
- Read the Architecture to understand the system design
- Check existing issues and pull requests to avoid duplicates
- Join discussions in GitHub Issues for major changes
Development Setup
Section titled “Development Setup”Prerequisites
Section titled “Prerequisites”Required Software
- Python 3.11 or higher
- Node.js 20 or higher
- npm or yarn
- Git
- SQLite 3
- ffmpeg (for subtitle processing)
- unrar-free (for archive extraction)
Optional Tools
- Docker and Docker Compose (for containerized development)
- Ollama (for local LLM testing)
- Sonarr/Radarr instances (for integration testing)
Clone the Repository
Section titled “Clone the Repository”git clone https://github.com/yourusername/sublarr.gitcd sublarrBackend Setup
Section titled “Backend Setup”-
Create a virtual environment
Terminal window cd backendpython -m venv venvsource venv/bin/activate # On Windows: venv\Scripts\activate -
Install dependencies
Terminal window pip install -r requirements.txtOder verwende das Setup-Script (empfohlen):
Terminal window # Windows (PowerShell)npm run setup:ps1# Linux/Mac (Bash)./scripts/setup-dev.sh -
Configure environment variables
Terminal window cp ../.env.example .env# Edit .env with boot fundamentals only (DB, paths, port, log level).Sublarr is UI-first since 0.88.0-beta — only 11 boot fundamentals are env-readable (see Environment Variables). Translation backends, providers, scanner, etc. configure via the UI on first run. For development, the typical
.envis just:SUBLARR_LOG_LEVEL=DEBUGSUBLARR_LOG_FORMAT=text -
Run the development server
Terminal window npm run dev:backendBackend will be available at
http://localhost:5765(DB is initialized automatically on first start)
Frontend Setup
Section titled “Frontend Setup”-
Install dependencies
Terminal window cd frontendnpm install -
Run the development server
Terminal window npm run devFrontend will be available at
http://localhost:3000with hot module reloading. -
The frontend development server proxies API requests to the backend
- Configured in
vite.config.ts - No CORS issues during development
- Configured in
Docker Setup (Alternative)
Section titled “Docker Setup (Alternative)”For testing the full production build locally:
# Build the imagedocker build -t sublarr:dev .
# Run with docker-composedocker-compose up -d
# View logsdocker-compose logs -f sublarrCode Style Guidelines
Section titled “Code Style Guidelines”Python (Backend)
Section titled “Python (Backend)”General Conventions
- Follow PEP 8 style guide
- Use 4 spaces for indentation (no tabs)
- Maximum line length: 100 characters
- Use type hints for function signatures
- Write docstrings for all public functions and classes
Naming Conventions
- Variables and functions:
snake_case - Classes:
PascalCase - Constants:
UPPER_SNAKE_CASE - Private methods:
_leading_underscore
Example
from typing import Optional, Listfrom pydantic import BaseModel
class SubtitleResult(BaseModel): """Represents a subtitle search result from a provider."""
provider: str language: str format: str score: int download_url: str
def is_ass_format(self) -> bool: """Check if this result is in ASS format.""" return self.format.lower() == "ass"
def search_subtitles(query: str, language: str) -> List[SubtitleResult]: """ Search for subtitles across all enabled providers.
Args: query: Search query (series/movie title) language: ISO 639-1 language code
Returns: List of subtitle results sorted by score """ # Implementation here passImport Order
- Standard library imports
- Third-party imports
- Local application imports
- Separate groups with blank lines
Error Handling
- Use specific exception types, not bare
except: - Log errors with appropriate context
- Raise custom exceptions for business logic errors
TypeScript (Frontend)
Section titled “TypeScript (Frontend)”General Conventions
- Use TypeScript strict mode
- Prefer interfaces over type aliases for object shapes
- Use const assertions for literal types
- No
anytype without explicit comment explaining why
Naming Conventions
- Variables and functions:
camelCase - React components:
PascalCase - Constants:
UPPER_SNAKE_CASE - Types and interfaces:
PascalCase
Example
interface SubtitleResult { provider: string; language: string; format: string; score: number; downloadUrl: string;}
const SubtitleCard: React.FC<{ result: SubtitleResult }> = ({ result }) => { const isAssFormat = result.format.toLowerCase() === 'ass';
return ( <div className="subtitle-card"> <span className={isAssFormat ? 'font-bold' : ''}> {result.provider} - {result.language} </span> </div> );};
export default SubtitleCard;React Component Guidelines
- Use functional components with hooks (no class components)
- Extract complex logic into custom hooks
- Prefer composition over prop drilling
- Use React.memo for expensive renders
- Keep components small and focused (< 200 lines)
Import Order
- React and third-party imports
- Local component imports
- Hook imports
- Utility imports
- Type imports (use
import type)
CSS/Tailwind
Section titled “CSS/Tailwind”Conventions
- Use Tailwind utility classes as primary styling method
- Extract repeated patterns into CSS components (not inline styles)
- Use semantic class names for custom CSS
- Follow mobile-first responsive design
- Use CSS variables for theme colors
Example
// Good: Tailwind utilities<div className="flex items-center justify-between p-4 bg-gray-100 rounded-lg">
// Good: Custom component class for repeated pattern<div className="subtitle-card">
// Avoid: Inline styles<div style={{ padding: '16px', backgroundColor: '#f0f0f0' }}>General Guidelines
Section titled “General Guidelines”Code Quality
- No trailing whitespace
- Files must end with a newline
- Use meaningful variable names (no single letters except loop counters)
- Keep functions short and focused (single responsibility)
- Comment complex logic, not obvious code
Git Commit Messages
- Use imperative mood: “Add feature” not “Added feature”
- First line: 50 characters or less, capitalized
- Blank line after first line if body follows
- Body: wrap at 72 characters, explain what and why (not how)
Example
feat: Add SubDL provider support
Implements SubDL provider with ZIP extraction and API key auth.
Closes #123Commit Prefixes
feat:New featurefix:Bug fixdocs:Documentation onlystyle:Formatting, no code changerefactor:Code restructuring, no behavior changetest:Adding or updating testschore:Maintenance tasks, dependencies
Testing
Section titled “Testing”Backend Tests
Section titled “Backend Tests”Running Tests
cd backendpytestpytest -v # Verbose outputpytest tests/test_providers.py # Specific fileWriting Tests
- Place tests in
backend/tests/directory - Name test files with
test_prefix - Use pytest fixtures for common setup
- Keep provider tests isolated (mock HTTP calls)
Example Test
import pytestfrom providers.opensubtitles import OpenSubtitlesProviderfrom providers.base import VideoQuery
@pytest.fixturedef provider(): return OpenSubtitlesProvider(api_key="test_key")
def test_search_returns_results(provider, mocker): # Mock HTTP call mock_response = {"data": [{"id": "123", "attributes": {...}}]} mocker.patch.object(provider.session, "get", return_value=mock_response)
query = VideoQuery( series="Attack on Titan", season=1, episode=1, language="en" ) results = provider.search(query)
assert len(results) > 0 assert results[0].provider == "opensubtitles"Test Coverage
- Backend: Aim for 80%+ coverage (enforced in CI)
- Frontend: Aim for 70%+ coverage (enforced in CI)
- Mock external services (Ollama, Sonarr, providers)
- Test error handling and edge cases
- Don’t test trivial getters/setters
Coverage Reports:
# Backend coveragecd backendpytest --cov=. --cov-report=html# Open htmlcov/index.html in browser
# Frontend coveragecd frontendnpm run test:coverage# Open coverage/index.html in browserFrontend Tests
Section titled “Frontend Tests”Running Tests
cd frontendnpm testnpm run test:coverageWriting Tests
- Use React Testing Library for component tests
- Test user interactions, not implementation details
- Mock API calls with MSW (Mock Service Worker)
Example Test
import { render, screen, fireEvent } from '@testing-library/react';import SubtitleCard from './SubtitleCard';
test('renders subtitle information', () => { const result = { provider: 'OpenSubtitles', language: 'en', format: 'ass', score: 150, downloadUrl: 'http://example.com/sub.ass' };
render(<SubtitleCard result={result} />);
expect(screen.getByText(/OpenSubtitles/)).toBeInTheDocument(); expect(screen.getByText(/en/)).toBeInTheDocument();});Integration Tests
Section titled “Integration Tests”Provider Testing
- Test against real provider APIs (optional)
- Configure provider keys via Settings → Providers in a dev instance
- Use separate API keys for testing
- Run manually before releases
Manual Testing Checklist
Section titled “Manual Testing Checklist”Before submitting a PR with UI changes:
- Test in Chrome, Firefox, Safari
- Test mobile responsive layout
- Test dark mode (if applicable)
- Test loading and error states
- Test WebSocket disconnection/reconnection
Pull Request Process
Section titled “Pull Request Process”Before Submitting
Section titled “Before Submitting”-
Fork the repository and create a branch from
masterTerminal window git checkout -b feature/my-new-feature -
Make your changes following the code style guidelines
-
Test your changes thoroughly
- Run backend tests:
cd backend && pytest - Run frontend tests:
cd frontend && npm test - Test manually in the browser
- Run backend tests:
-
Update documentation if needed
- Update CHANGELOG.md with your changes
- Add/update docstrings and comments
- Update API.md for new endpoints
-
Commit your changes with clear messages
Terminal window git add .git commit -m "feat: Add new provider support"
Submitting the PR
Section titled “Submitting the PR”-
Push to your fork
Terminal window git push origin feature/my-new-feature -
Create a Pull Request on GitHub
- Use a clear, descriptive title
- Fill out the PR template (if provided)
- Link related issues with “Closes #123”
-
PR Description Should Include
- What changes were made
- Why these changes are needed
- How to test the changes
- Screenshots (for UI changes)
- Breaking changes (if any)
PR Review Process
Section titled “PR Review Process”- Automated Checks: CI/CD runs tests automatically
- Code Review: Maintainer reviews code and provides feedback
- Address Feedback: Make requested changes, push to same branch
- Approval: PR approved when ready to merge
- Merge: Maintainer merges PR to master
PR Guidelines
- One feature/fix per PR (keep it focused)
- Keep PRs small (< 500 lines if possible)
- Respond to feedback within a week
- Rebase on master if conflicts arise
- Squash commits before merge (maintainer will do this)
Reporting Issues
Section titled “Reporting Issues”Bug Reports
Section titled “Bug Reports”Before Reporting
- Search existing issues to avoid duplicates
- Test on the latest version
- Gather logs and error messages
Issue Template
## Bug DescriptionClear description of the bug
## Steps to Reproduce1. Go to '...'2. Click on '...'3. See error
## Expected BehaviorWhat should happen
## Actual BehaviorWhat actually happens
## Environment- Sublarr version:- Docker or local:- OS:- Browser (if frontend issue):
## LogsPaste relevant logs hereFeature Requests
Section titled “Feature Requests”Template
## Feature DescriptionWhat feature would you like to see?
## Use CaseWhy is this feature needed? What problem does it solve?
## Proposed SolutionHow would you implement this?
## Alternatives ConsideredWhat other approaches did you think about?Adding New Features
Section titled “Adding New Features”Adding a New Provider
Section titled “Adding a New Provider”See Plugin Development for detailed instructions on adding subtitle providers.
Quick Steps
- Create
providers/newprovider.pyextendingSubtitleProvider - Implement
search(),download(),health_check()methods - Add config settings to
config.py - Register in
providers/__init__.pyPROVIDER_REGISTRY - Add to
.env.examplewithSUBLARR_prefix - Write tests in
tests/test_providers.py - Update PROVIDERS.md documentation
Adding a New API Endpoint
Section titled “Adding a New API Endpoint”Steps
- Add route handler in a Blueprint under
backend/routes/ - Define Pydantic models for request/response validation
- Update
frontend/src/api/client.tswith TypeScript types - Add React Query hook in
frontend/src/hooks/useApi.ts - Document endpoint in
docs/API.md - Write tests for endpoint
Example
from pydantic import BaseModel
class MyRequest(BaseModel): param: str
class MyResponse(BaseModel): result: str
@api_v1.route("/my-endpoint", methods=["POST"])def my_endpoint(): req = MyRequest(**request.json) # Process request return jsonify(MyResponse(result="success").dict())export const callMyEndpoint = async (param: string): Promise<string> => { const response = await apiClient.post('/my-endpoint', { param }); return response.data.result;};Adding Database Tables
Section titled “Adding Database Tables”Steps
- Define schema in
backend/db/(add table to the relevant domain module) - Add version check and migration logic
- Create model class and helper functions
- Update relevant API endpoints
- Add frontend UI if needed
Migration Pattern
def init_db(): # ... existing tables ...
# Check for new table cursor.execute("SELECT name FROM sqlite_master WHERE type='table' AND name='my_new_table'") if not cursor.fetchone(): cursor.execute(""" CREATE TABLE my_new_table ( id INTEGER PRIMARY KEY AUTOINCREMENT, created_at TEXT NOT NULL, ... ) """) conn.commit()License
Section titled “License”By contributing to Sublarr, you agree that your contributions will be licensed under the GNU General Public License v3.0 (GPL-3.0).
All submitted code must be compatible with GPL-3.0. If you include code from other projects:
- Ensure the original license is compatible with GPL-3.0
- Include proper attribution in comments
- Update ACKNOWLEDGMENTS.md if needed
Questions?
Section titled “Questions?”- Open a GitHub Discussion for general questions
- Join the community chat (if available)
- Tag maintainers in issues for urgent matters
Thank you for contributing to Sublarr!