Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
2346c40
feat: add ApiKeys table and model
Dec 29, 2025
850ee7b
feat: add apiKeyModule with security features
Dec 29, 2025
a0ef720
feat: add API key auth to verifyToken middleware
Dec 29, 2025
c755f86
feat: add API key routes and download endpoint
Dec 29, 2025
7f9934d
feat: add logger redaction and rate limiting for API keys
Dec 29, 2025
72f54e5
feat: add ApiKeysSection component with bookmarklet
Dec 29, 2025
7682998
feat: integrate ApiKeysSection in Configuration page
Dec 29, 2025
43ca979
feat: add download source indicator for API-triggered downloads
Dec 29, 2025
b4b6fa4
docs: add API integration guide
Dec 29, 2025
50166ec
fix: correct InfoTooltip prop name
Dec 29, 2025
b556bfa
fix: rate limiter IPv6 validation error
Dec 29, 2025
f5cb315
test: add comprehensive API key security tests
Dec 29, 2025
7ae79b4
docs: clarify API keys support single videos only
Dec 29, 2025
17b5242
feat: implement dev branch workflow with RC builds
Dec 29, 2025
4ff0f47
docs: update CONTRIBUTING.md and DEVELOPMENT.md for dev branch workflow
Dec 29, 2025
1d985c7
feat: add --dev flag to start scripts for bleeding-edge builds
Dec 29, 2025
9e81cf7
chore: add dynamic run-name to production release workflow
Dec 29, 2025
67821f4
feat: make API keys section collapsible and add swagger docs
Dec 29, 2025
1069361
refactor: remove unused getApiKey function
Dec 29, 2025
0cf87ba
Add security enhancements: delete confirmation, input sanitization, a…
Dec 29, 2025
66757b0
Merge pull request #386 from DialmasterOrg/feature/378-improved-branc…
dialmaster Dec 30, 2025
d62b1cd
Add frontend tests for API keys and download source indicator
Dec 30, 2025
fe58614
Add usage statistics tracking for API keys
Dec 30, 2025
08ca16a
Fix migration helper function name
Dec 30, 2025
dee27de
docs: add API key settings to CONFIG and USAGE_GUIDE
Dec 30, 2025
c6ffc3c
fix: make temp path test platform-agnostic
Dec 30, 2025
ccb21d7
fix: resolve ESLint waitFor multiple assertions errors
Dec 30, 2025
4a5dd6a
fix: change RC tag format from version-based to dev-rc.<sha>
Dec 30, 2025
9c80df6
Merge pull request #388 from DialmasterOrg/feature/378-improved-branc…
dialmaster Dec 30, 2025
d06963e
fix: filter dev tags from version update notification
Dec 30, 2025
3637d11
test: make version filter test more flexible
Dec 30, 2025
2c8d073
Merge pull request #390 from DialmasterOrg/feature/378-improved-branc…
dialmaster Dec 31, 2025
fb7c014
fix: theme-aware color for dark mode support
dialmaster Jan 3, 2026
4691903
Merge pull request #389 from DialmasterOrg/feature/api-keys-bookmarklet
dialmaster Jan 3, 2026
556d2ba
ix: allow CORS preflight for bookmarklets behind external auth proxies
dialmaster Jan 3, 2026
e645c60
Merge pull request #393 from DialmasterOrg/feature/api-keys-bookmarklet
dialmaster Jan 4, 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
2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ name: CI - Lint and Test

on:
pull_request:
branches: [ main ]
branches: [ main, dev ]

permissions:
contents: read
Expand Down
101 changes: 101 additions & 0 deletions .github/workflows/release-rc.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
name: Release Candidate Build

on:
push:
branches: [ dev ]

concurrency:
group: release-rc-${{ github.ref }}
cancel-in-progress: true

jobs:
release-rc:
name: Build & Push RC Image
runs-on: ubuntu-latest
# Skip if commit message contains [skip ci]
if: "!contains(github.event.head_commit.message, '[skip ci]')"
permissions:
contents: read
packages: write

steps:
- name: Checkout code
uses: actions/checkout@v4
with:
fetch-depth: 0

- name: Get version info
id: version
run: |
# Get short SHA for unique RC identifier
SHORT_SHA=$(git rev-parse --short HEAD)

# Create RC tag: dev-rc.<sha> (not tied to a specific version)
RC_TAG="dev-rc.${SHORT_SHA}"

echo "rc_tag=${RC_TAG}" >> $GITHUB_OUTPUT
echo "short_sha=${SHORT_SHA}" >> $GITHUB_OUTPUT

echo "🏷️ RC tag: ${RC_TAG}"

- name: Set up Node.js
uses: actions/setup-node@v4
with:
node-version: '20'

- name: Install server dependencies
run: npm ci --ignore-scripts

- name: Install client dependencies
run: |
cd client
npm ci

- name: Build client
run: |
cd client
npm run build
echo "✅ Client build successful"

- name: Set up QEMU (multi-arch)
uses: docker/setup-qemu-action@v3

- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3

- name: Login to Docker Hub
uses: docker/login-action@v3
with:
username: ${{ vars.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}

- name: Build and push RC Docker images
uses: docker/build-push-action@v5
with:
context: .
push: true
platforms: linux/amd64,linux/arm64
tags: |
${{ vars.DOCKERHUB_USERNAME }}/youtarr:${{ steps.version.outputs.rc_tag }}
${{ vars.DOCKERHUB_USERNAME }}/youtarr:dev-latest
no-cache: true

- name: Summary
run: |
echo "## 🚀 Release Candidate Published" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "### Docker Images" >> $GITHUB_STEP_SUMMARY
echo "- \`${{ vars.DOCKERHUB_USERNAME }}/youtarr:${{ steps.version.outputs.rc_tag }}\`" >> $GITHUB_STEP_SUMMARY
echo "- \`${{ vars.DOCKERHUB_USERNAME }}/youtarr:dev-latest\`" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "### Pull Commands" >> $GITHUB_STEP_SUMMARY
echo "\`\`\`bash" >> $GITHUB_STEP_SUMMARY
echo "# Specific RC version" >> $GITHUB_STEP_SUMMARY
echo "docker pull ${{ vars.DOCKERHUB_USERNAME }}/youtarr:${{ steps.version.outputs.rc_tag }}" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "# Latest dev build" >> $GITHUB_STEP_SUMMARY
echo "docker pull ${{ vars.DOCKERHUB_USERNAME }}/youtarr:dev-latest" >> $GITHUB_STEP_SUMMARY
echo "\`\`\`" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "⚠️ **Note:** This is a release candidate for testing. Use \`latest\` for stable releases." >> $GITHUB_STEP_SUMMARY

8 changes: 6 additions & 2 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
name: Create Release V2
run-name: ${{ inputs.dry_run && 'Create Release V2 — Dry Run' || 'Create Release V2' }}
name: Production Release
run-name: ${{ github.event_name == 'workflow_dispatch' && (inputs.dry_run && 'Production Release — Dry Run' || 'Production Release — Manual') || 'Production Release — Auto' }}

on:
push:
branches: [ main ]
workflow_dispatch:
inputs:
dry_run:
Expand All @@ -18,6 +20,8 @@ jobs:
release:
name: ${{ inputs.dry_run && 'Release (Dry Run)' || 'Release' }}
runs-on: ubuntu-latest
# Skip if commit message contains [skip ci]
if: "!contains(github.event.head_commit.message, '[skip ci]')"
permissions:
contents: write
packages: write
Expand Down
71 changes: 59 additions & 12 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -169,12 +169,41 @@ Husky automatically runs these checks before each commit:

If any check fails, the commit is blocked. Fix the issues and try again.

## Branching Strategy

Youtarr uses a **dev → main** branching model to ensure stable releases:

```
feature/xxx ──┐
feature/yyy ──┼──→ dev (bleeding edge) ──→ main (stable releases)
fix/zzz ──────┘
```

### Branch Overview

| Branch | Purpose | Docker Tag |
|--------|---------|------------|
| `main` | Stable, released code | `latest`, `vX.X.X` |
| `dev` | Integration branch for upcoming release | `dev-latest`, `dev-rc.<sha>` |
| `feature/*`, `fix/*` | Individual changes | None |

### Workflow Summary

1. **Feature development**: Branch from `dev`, create PR back to `dev`
2. **RC builds**: Merging to `dev` automatically builds release candidate images
3. **Releases**: PR from `dev` → `main` triggers a full release
4. **Hotfixes**: Can merge directly to `main` (then merge back to `dev`)

## Pull Request Process

### Before Submitting

1. **Create a feature branch** from `main`:
1. **Create a feature branch** from `dev`:
```bash
git checkout dev
git pull origin dev
git checkout -b feat/your-feature-name
# or
git checkout -b fix/issue-description
Expand All @@ -195,10 +224,11 @@ If any check fails, the commit is blocked. Fix the issues and try again.

### Submitting Your PR

When you're ready, push your branch and create a pull request on GitHub. Your PR will be reviewed by the maintainer.
When you're ready, push your branch and create a pull request **targeting the `dev` branch** on GitHub. Your PR will be reviewed by the maintainer.

**PR Checklist:**

- [ ] PR targets `dev` branch (not `main`)
- [ ] Tests pass locally (`npm test`)
- [ ] Coverage meets 70% threshold
- [ ] Conventional commit format used
Expand All @@ -221,17 +251,22 @@ When you're ready, push your branch and create a pull request on GitHub. Your PR
- Feedback may be provided for improvements
- Additional changes may be requested

3. **Merge and release**
- Once approved, the maintainer will merge your PR
- Releases are created manually by the maintainer
- Version bumps are automatic based on your commit message prefix
- Docker images are automatically built and published
3. **Merge to dev**
- Once approved, your PR is merged to `dev`
- A release candidate (RC) Docker image is automatically built
- RC images are tagged as `dev-latest` and `dev-rc.<commit-sha>`

4. **Release to main**
- When ready, the maintainer creates a PR from `dev` → `main`
- Merging to `main` triggers the full release workflow
- Version bumps are automatic based on commit message prefixes
- Production Docker images are tagged as `latest` and `vX.X.X`

## CI/CD Information

### Checks on Pull Requests

Every PR triggers automated checks:
Every PR (to `dev` or `main`) triggers automated checks:

- **ESLint**: Code style and linting
- **TypeScript**: Type checking and compilation
Expand All @@ -255,15 +290,27 @@ If CI checks fail:
3. **Test failures**: Run `npm test` to see which tests failed
4. **Coverage drops**: Add tests to increase coverage above 70%

### Release Automation
### Release Candidate Builds (dev branch)

When code is merged to `dev`, an RC build is automatically triggered:
- Builds multi-architecture Docker images (amd64 + arm64)
- Pushes to Docker Hub with tags:
- `dialmaster/youtarr:dev-latest` (always the latest dev build)
- `dialmaster/youtarr:dev-rc.<commit-sha>` (specific RC build)

These RC images allow testing bleeding-edge features before stable release.

### Production Releases (main branch)

Releases are triggered manually by the maintainer via GitHub Actions. The release workflow:
When code is merged from `dev` to `main`, a production release is triggered:
- Analyzes conventional commit messages to determine version bump
- Updates version in `package.json`
- Generates `CHANGELOG.md` entries
- Creates GitHub release
- Creates GitHub release with release notes
- Builds multi-architecture Docker images (amd64 + arm64)
- Publishes to Docker Hub (`dialmaster/youtarr`)
- Publishes to Docker Hub with tags:
- `dialmaster/youtarr:latest` (stable release for end-users)
- `dialmaster/youtarr:vX.X.X` (specific version)

You don't need to worry about versioning or releases - just use the correct commit message prefix.

Expand Down
39 changes: 39 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,45 @@ https://github.com/user-attachments/assets/cc153624-c905-42c2-8ee9-9c213816be3a
- Bash shell (Git Bash for Windows)
> **Heads up:** Youtarr runs exclusively via Docker; direct `npm start`/Node deployments are unsupported.

## Using Development Builds

Want to try new features before they're officially released? Youtarr offers bleeding-edge development builds that contain the latest merged changes.

> ⚠️ **Warning:** Dev builds are not fully tested and may be unstable. Use at your own risk, and expect potential bugs or breaking changes. Recommended for testing/feedback only.

### Option 1: Using the start script (recommended)

```bash
./start.sh --dev --pull-latest
```

This pulls and runs the `dev-latest` image, which is automatically built whenever changes are merged to the `dev` branch.

### Option 2: Manual configuration

If you're not using the start script, set the `YOUTARR_IMAGE` environment variable in your `.env` file or docker-compose command:

```bash
# In .env file
YOUTARR_IMAGE=dialmaster/youtarr:dev-latest
```

Or with docker-compose directly:

```bash
YOUTARR_IMAGE=dialmaster/youtarr:dev-latest docker compose up -d
```

### Switching back to stable

Simply run without the `--dev` flag:

```bash
./start.sh --pull-latest
```

Or remove/comment out the `YOUTARR_IMAGE` line in your `.env` file to use the default stable `latest` tag.

## Documentation

### Getting Started
Expand Down
1 change: 1 addition & 0 deletions client/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

7 changes: 7 additions & 0 deletions client/src/components/Configuration.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import { DownloadPerformanceSection } from './Configuration/sections/DownloadPer
import { AdvancedSettingsSection } from './Configuration/sections/AdvancedSettingsSection';
import { AutoRemovalSection } from './Configuration/sections/AutoRemovalSection';
import { AccountSecuritySection } from './Configuration/sections/AccountSecuritySection';
import ApiKeysSection from './Configuration/sections/ApiKeysSection';
import { SaveBar } from './Configuration/sections/SaveBar';
import {
usePlexConnection,
Expand Down Expand Up @@ -269,6 +270,12 @@ function Configuration({ token }: ConfigurationProps) {
setSnackbar={setSnackbar}
/>

<ApiKeysSection
token={token}
apiKeyRateLimit={config.apiKeyRateLimit}
onRateLimitChange={(value) => handleConfigChange({ apiKeyRateLimit: value })}
/>

<SaveBar
hasUnsavedChanges={hasUnsavedChanges}
isLoading={isLoading}
Expand Down
Loading