We're always looking for people to help make Listenarr even better! There are a number of ways to contribute, from documentation to development.
Setup guides, FAQ, troubleshooting tips - the more information we have in the documentation, the better. Help us improve:
-
Wiki (coming soon)
-
Code comments and inline documentation
-
README improvements
-
Tutorial videos or blog posts
-
Canonical contributor guidance and AI-agent rules: see
.github/AGENTS.md,.github/CLAUDE.mdand.github/RULES.md
- Visual Studio 2022 or higher (https://www.visualstudio.com/vs/). The community version is free and works fine.
- Rider (optional alternative to Visual Studio, preferred by many) (https://www.jetbrains.com/rider/)
- VS Code (recommended for frontend) (https://code.visualstudio.com/)
- Git (https://git-scm.com/downloads)
- Node.js (Node 20.x or higher) (https://nodejs.org/)
- .NET 8.0 SDK or higher (https://dotnet.microsoft.com/download)
- Fork Listenarr on GitHub
- Clone the repository to your development machine
git clone https://github.com/YOUR-USERNAME/Listenarr.git cd Listenarr - Install root dependencies (for concurrently)
npm install
- Install frontend dependencies
cd fe npm install cd ..
- Restore .NET dependencies
cd listenarr.api dotnet restore cd ..
- Start development servers Option A - Single command (recommended, runs both API and web):
npm run devOption B - Start services separately (useful for backend debugging):
# Terminal 1 - Backend (fast restart on code changes)
cd listenarr.api
dotnet watch run
# Terminal 2 - Frontend
cd fe
npm run dev- Open your browser
- Frontend: http://localhost:5173
- Backend API: http://localhost:4545
- Open
listenarr.slnin Visual Studio or Rider - Set
listenarr.apias the startup project - Press F5 to start debugging
- The API will be available at http://localhost:4545
Note: there is also a watch task available in the workspace tasks that runs dotnet watch run across the solution when you prefer a single task for backend hot-reloads.
- Open the root folder in VS Code
- Use the provided launch configurations in
.vscode/launch.json - Press F5 to start debugging both frontend and backend
- Update the API URL in
fe/src/services/api.tsto use your development machine's IP address instead oflocalhost - Example:
http://192.168.1.100:4545instead ofhttp://localhost:4545
Before you start:
-
If you're adding a new feature, please check GitHub Issues to see if it's already requested
-
Comment on the issue so work isn't duplicated
-
If adding something not already requested, please create an issue first to discuss it
-
Reach out on Discussions if you have questions
-
Run frontend tests:
cd fe && npm test(the frontend uses Vitest/Vite; checkfe/package.jsonfor exact scripts) -
Rebase from Listenarr's
developbranch, don't merge -
Make meaningful commits, or squash them before submitting PR
-
Feel free to make a pull request before work is complete (mark as draft) - this lets us see progress and provide feedback
-
Add tests where applicable (unit/integration)
-
Commit with *nix line endings for consistency (We checkout Windows and commit *nix)
-
One feature/bug fix per pull request to keep things clean and easy to understand
Code style:
- Backend (C#): Use 4 spaces instead of tabs (default in VS 2022/Rider)
- Frontend (Vue/TS): Use 2 spaces for indentation
- Follow existing code patterns and conventions
- Use meaningful variable and function names
- Add comments for complex logic
This project follows a layered pattern: domain models in listenarr.domain, EF mappings and DbContext in listenarr.infrastructure, and services/controllers in listenarr.api. Follow these rules when working with EF and DI:
-
Where to add EF mappings:
- Add EF model configuration and ValueConverters in
listenarr.infrastructure. Keep database-specific concerns (migrations, pragmas, converters) in Infrastructure. - Centralized converters are in
listenarr.infrastructure/Persistence/Converters/JsonValueConverters.cs. Add other shared converters there.
- Add EF model configuration and ValueConverters in
-
DbContext registration:
- Use
AddDbContextFactory<ListenArrDbContext>for hosted/background services that need DbContext outside of HTTP request scope. - Also keep
AddDbContext<ListenArrDbContext>for compatibility with controllers/endpoints that use scoped DbContext. - The helper extension
Listenarr.Api.Extensions.ServiceRegistrationExtensions.AddListenarrPersistencecentralizes these registrations. Call it fromProgram.csto ensure consistent setup.
- Use
-
Pattern for hosted services:
- Inject
IDbContextFactory<ListenArrDbContext>into hosted/background services and create contexts withawait factory.CreateDbContextAsync(cancellationToken). - Dispose contexts promptly and avoid storing DbContext as a field.
- Inject
-
Test host behavior:
- Integration tests use a test partial of Program. To patch the test host, implement
Program.Testing.cs(or theApplyTestHostPatcheshook) to callAddListenarrPersistenceand any test-specific overrides (e.g. a test SQLite path). - Disable or mock heavy external installers (Playwright) in the test host by overriding configuration with an in-memory setting:
builder.Configuration.AddInMemoryCollection(new Dictionary<string,string>{{ "Playwright:Enabled","false"}}). - This prevents CI/tests from spawning external processes while keeping DI consistent.
- Integration tests use a test partial of Program. To patch the test host, implement
-
New adapters / HttpClients:
- Register typed or named HttpClients in
listenarr.apiusing theAddListenarrHttpClientsextension or directly inProgram.cs. - Register adapter interfaces in the adapters module (see
listenarr.api/Extensions/ServiceRegistrationExtensions.cs). - If a factory delegate is required (resolve adapter by id), register a
Func<string, IDownloadClientAdapter>as a singleton that resolves registered adapters.
- Register typed or named HttpClients in
-
Testing tips:
- Add unit tests for ValueConverters and ValueComparers to ensure JSON behavior is stable (null handling, empty JSON).
- Use
WebApplicationFactory<Program>for integration tests and applyWithWebHostBuilderwhen you need to override services. - Use the test-host patching approach to keep tests hermetic (no external network or process calls).
Testing:
- Run backend tests:
cd listenarr.api && dotnet test - Run frontend tests:
cd fe && npm run test:unit - Ensure all tests pass before submitting PR
Branch naming:
- Create PRs from feature branches, not from
developin your fork - Use meaningful branch names that describe what is being added/fixed
Good examples:
feature/audible-integrationfeature/download-queuebugfix/search-resultsenhancement/ui-improvements
Bad examples:
new-featurefix-bugpatchdevelop
PR process:
- Target branch: Only make pull requests to
canary, nevermainordevelop- PRs to
mainanddevelopwill be commented on and closed
- PRs to
- Description: Provide a clear description of what your PR does
- Reference related issues (e.g., "Fixes #123")
- Include screenshots for UI changes
- List breaking changes if any
- Review: You'll probably get comments or questions from us
- These are to ensure consistency and maintainability
- Don't take them personally - we appreciate your contribution!
- Response time: We'll try to respond as soon as possible
- If it's been a few days without response, please ping us
- We may have missed the notification
PR checklist:
- Code follows project style guidelines
- Self-review of code completed
- Comments added for complex logic
- Tests added/updated (if applicable)
- All tests pass
- No console errors or warnings
- Documentation updated (if needed)
- Rebased on latest
canarybranch
If you want to explore the API using Swagger:
- Start the backend API
cd listenarr.api dotnet run - Navigate to http://localhost:4545/swagger
- You can test all API endpoints directly from the Swagger UI
Listenarr/
├── listenarr.api/ # Backend API (.NET Core)
│ ├── Controllers/ # API endpoints
│ ├── Models/ # Data models
│ ├── Services/ # Business logic
│ └── Program.cs # Application entry
├── fe/ # Frontend (Vue.js)
│ ├── src/
│ │ ├── components/ # Reusable Vue components
│ │ ├── views/ # Page components
│ │ ├── stores/ # Pinia state management
│ │ ├── services/ # API client services
│ │ └── types/ # TypeScript type definitions
│ └── public/ # Static assets
├── tests/ # Test scripts
├── .github/ # GitHub configuration
├── docker-compose.yml # Docker setup
└── README.md # Main documentation
Backend:
- ASP.NET Core Web API
- Entity Framework Core with SQLite
- C# 12 / .NET 8.0+
Frontend:
- Vue 3 (Composition API)
- TypeScript
- Pinia (state management)
- Vue Router
- Vite (build tool)
We plan to support multiple languages in the future. If you'd like to help translate Listenarr into your language, please let us know on Discussions.
Got an idea for a new feature? Here's how to suggest it:
- Check GitHub Discussions to see if it's already been suggested
- If not, create a new discussion in the "Ideas" category
- Clearly describe the feature and why it would be useful
- Include mockups or examples if applicable
Found a bug? Please report it!
- Check GitHub Issues to see if it's already reported
- If not, create a new issue with:
- Clear title describing the bug
- Steps to reproduce
- Expected behavior
- Actual behavior
- Screenshots (if applicable)
- Environment details (OS, browser, .NET version, Node version)
We are committed to providing a welcoming and inspiring community for all. Please be respectful and constructive in your interactions with other contributors.
- Be respectful and inclusive
- Provide constructive feedback
- Accept constructive criticism gracefully
- Focus on what's best for the community
- Show empathy towards other community members
- Harassment, discrimination, or offensive comments
- Personal attacks or insults
- Trolling or inflammatory comments
- Publishing others' private information
- Any conduct that would be inappropriate in a professional setting
If you have any questions about contributing, please:
- Check the Wiki (coming soon)
- Ask in GitHub Discussions
- Open an issue if you think something is unclear in this guide
- Keep contracts (interfaces, DTOs, domain models) in
listenarr.applicationorlistenarr.domain. - Keep framework-dependent implementations (EF Core, HttpClients, filesystem) in
listenarr.infrastructure. listenarr.apishould only compose services, host controllers, and register DI; do not add new interfaces that duplicate application/infrastructure contracts.- Migration checklist for misplaced interface + implementation found in
listenarr.api:- Move the interface/DTO to
listenarr.applicationorlistenarr.domain. - Move the concrete implementation to
listenarr.infrastructure/Services. - Add registration in
listenarr.infrastructure/Extensions/InfrastructureServiceRegistrationExtensions.cs(e.g.,services.AddScoped<IFoo, Foo>();). - In
listenarr.api/Program.cscall the infrastructure registration extension instead of registering types inline. - Delete the old API placeholder files and run
dotnet testto verify no regressions.
- Move the interface/DTO to
- Add a small DI/registration unit test (DependencyInjectionTests) that asserts required services are resolvable; run it early in CI to catch layering regressions.
Thank you for contributing to Listenarr! 🎵📚