This guide covers how to set up a development environment and contribute to Video Vault.
- Python 3.12 or 3.13
- uv package manager
- Git
git clone <repository-url>
cd video-vault# Install all dependencies including dev dependencies
uv sync# Run the application
uv run video-vault
# Or run directly with Python
uv run python -m video_vault.mainvideo-vault/
├── video_vault/ # Main package
│ ├── main.py # Application entry point
│ └── src/ # Source code
│ ├── core/ # Core business logic
│ │ ├── downloads.py # Download functionality
│ │ ├── security.py # Encryption/keyring
│ │ ├── ffmpeg.py # FFmpeg integration
│ │ └── consts.py # Constants
│ ├── db/ # Database layer
│ │ ├── models.py # Django models
│ │ ├── setup.py # Django configuration
│ │ └── migrations/ # Database migrations
│ └── ui/ # User interface
│ ├── stylesheet.py # Global styles
│ ├── windows/ # Main window
│ └── pages/ # UI pages
│ ├── downloads.py # Downloads page
│ ├── add_downloads.py # Browser page
│ └── player.py # Player page
├── tests/ # Test suite
├── docs/ # Documentation
└── pyproject.toml # Project configuration
- PySide6: Qt for Python - provides the UI framework
- winipyside: Custom framework built on PySide6 for page-based navigation
- yt-dlp: Downloads videos from various platforms
- FFmpeg: Video format conversion (bundled via imageio-ffmpeg)
- Django ORM: Database abstraction layer
- SQLite: Local database storage
- winidjango: Custom Django utilities
- cryptography: AES-GCM encryption
- keyring: Secure key storage in system keyring
# Run all tests
uv run pytest
# Run specific test file
uv run pytest tests/test_video_vault/test_main.py
# Run with coverage
uv run pytest --cov=video_vault# Run linter
uv run ruff check .
# Auto-fix linting issues
uv run ruff check --fix .
# Run type checker
uv run mypy .
# Run security checks
uv run bandit -r video_vault/When you modify models in video_vault/src/db/models.py:
# Create new migration
uv run python video_vault/src/db/make_migrations.py
# Migrations are automatically applied on app startup# Install pre-commit hooks
uv run pre-commit install
# Run hooks manually
uv run pre-commit run --all-files-
Startup (
main.py):- Initialize Django and database
- Create Qt application
- Apply global stylesheet
- Show main window
-
Main Window (
ui/windows/main.py):- Discovers all page classes
- Sets up page navigation
- Shows Downloads page by default
-
Page Lifecycle:
pre_setup(): Initialize UI componentssetup(): Configure layout and widgetspost_setup(): Final setup and connections
- User clicks download button in browser page
DownloadWorkerthread spawns- yt-dlp downloads video to temp directory
- FFmpeg converts to MP4 format
- Video is encrypted with AES-GCM
- Encrypted file saved to media directory
- Database record created
- UI updated with new video
-
Key Management:
- Key stored in system keyring
- Retrieved via
get_or_create_app_aes_gcm() - Same key used for all videos
-
Encryption (during download):
- Read unencrypted video data
- Encrypt with
EncryptedPyQFile.encrypt_data_static() - Save encrypted data to disk
-
Decryption (during playback):
EncryptedPyQFileQIODevice wraps encrypted file- Decrypts data on-the-fly as player reads
- No unencrypted data written to disk
- Follow PEP 8 guidelines
- Use Google-style docstrings
- Type hints required for all functions
- Maximum line length: 88 characters (Ruff default)
Use conventional commit format:
feat: add new feature
fix: fix bug
docs: update documentation
test: add tests
refactor: refactor code
- Fork the repository
- Create a feature branch
- Make your changes
- Run tests and linting
- Submit a pull request
# Build with PyInstaller
uv run pyinstaller video_vault.specThe executable will be in the dist/ directory.
If you encounter Qt-related errors:
# Reinstall PySide6
uv pip install --force-reinstall PySide6If database migrations fail:
# Delete database and start fresh
rm -rf ~/.local/share/VideoVault/db/Ensure you're running commands with uv run
to use the correct virtual environment.