diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..c4c60b7 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,18 @@ +node_modules +.git +.gitignore +.claude +.svelte-kit +build +dist +.env +.env.local +.vscode +.idea +target +*.apk +*.aab +*.log +coverage +src-tauri/gen +src-tauri/target diff --git a/.gitea/workflows/build-and-test.yml b/.gitea/workflows/build-and-test.yml new file mode 100644 index 0000000..dd415a7 --- /dev/null +++ b/.gitea/workflows/build-and-test.yml @@ -0,0 +1,81 @@ +name: '🏗️ Build and Test JellyTau' + +on: + push: + branches: + - master + paths-ignore: + - '**/*.md' + pull_request: + branches: + - master + paths-ignore: + - '**/*.md' + workflow_dispatch: + +jobs: + build: + name: Build APK and Run Tests + runs-on: ubuntu-latest + container: + image: gitea.tourolle.paris/dtourolle/jellytau-builder:latest + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Cache Rust dependencies + uses: actions/cache@v3 + with: + path: | + ~/.cargo/registry + ~/.cargo/git + src-tauri/target + key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }} + restore-keys: | + ${{ runner.os }}-cargo- + + - name: Cache Node dependencies + uses: actions/cache@v3 + with: + path: | + ~/.bun/install/cache + node_modules + key: ${{ runner.os }}-bun-${{ hashFiles('**/bun.lock') }} + restore-keys: | + ${{ runner.os }}-bun- + + - name: Install dependencies + run: | + bun install + + - name: Run frontend tests + run: bun test + + - name: Run Rust tests + run: | + cd src-tauri + cargo test + cd .. + + - name: Build frontend + run: bun run build + + - name: Build Android APK + id: build + run: | + mkdir -p artifacts + bun run tauri android build --apk true + + # Find the generated APK file + ARTIFACT=$(find src-tauri/gen/android/app/build/outputs/apk -name "*.apk" -type f -print -quit) + echo "artifact=${ARTIFACT}" >> $GITHUB_OUTPUT + echo "Found artifact: ${ARTIFACT}" + + - name: Upload build artifact + uses: actions/upload-artifact@v3 + with: + name: jellytau-apk + path: ${{ steps.build.outputs.artifact }} + retention-days: 30 + if-no-files-found: error diff --git a/BUILD-BUILDER-IMAGE.md b/BUILD-BUILDER-IMAGE.md new file mode 100644 index 0000000..850965f --- /dev/null +++ b/BUILD-BUILDER-IMAGE.md @@ -0,0 +1,156 @@ +# Building and Pushing the JellyTau Builder Image + +This document explains how to create and push the pre-built builder Docker image to your registry for use in Gitea Act CI/CD. + +## Prerequisites + +- Docker installed and running +- Access to your Docker registry (e.g., `gitea.tourolle.paris`) +- Docker registry credentials configured (`docker login`) + +## Building the Builder Image + +### Step 1: Build the Image Locally + +```bash +# From the project root +docker build -f Dockerfile.builder -t jellytau-builder:latest . +``` + +This creates a local image with: +- All system dependencies +- Rust with Android targets +- Android SDK and NDK +- Node.js and Bun +- All build tools pre-installed + +### Step 2: Tag for Your Registry + +Replace `gitea.tourolle.paris/dtourolle` with your actual registry path: + +```bash +docker tag jellytau-builder:latest gitea.tourolle.paris/dtourolle/jellytau-builder:latest +``` + +### Step 3: Login to Your Registry + +If not already logged in: + +```bash +docker login gitea.tourolle.paris +``` + +### Step 4: Push to Registry + +```bash +docker push gitea.tourolle.paris/dtourolle/jellytau-builder:latest +``` + +## Complete One-Liner + +```bash +docker build -f Dockerfile.builder -t jellytau-builder:latest . && \ +docker tag jellytau-builder:latest gitea.tourolle.paris/dtourolle/jellytau-builder:latest && \ +docker push gitea.tourolle.paris/dtourolle/jellytau-builder:latest +``` + +## Verifying the Build + +Check that the image was pushed successfully: + +```bash +# List images in your registry (depends on registry API support) +docker search gitea.tourolle.paris/dtourolle/jellytau-builder + +# Or pull and test locally +docker pull gitea.tourolle.paris/dtourolle/jellytau-builder:latest +docker run -it gitea.tourolle.paris/dtourolle/jellytau-builder:latest bun --version +``` + +## Using in CI/CD + +The workflow at `.gitea/workflows/build-and-test.yml` automatically uses: +```yaml +container: + image: gitea.tourolle.paris/dtourolle/jellytau-builder:latest +``` + +Once pushed, your CI/CD pipeline will use this pre-built image instead of installing everything during the build, saving significant time. + +## Updating the Builder Image + +When dependencies change (new Rust version, Android SDK update, etc.): + +1. Update `Dockerfile.builder` with the new configuration +2. Rebuild and push with a new tag: + +```bash +docker build -f Dockerfile.builder -t jellytau-builder:v1.2.0 . +docker tag jellytau-builder:v1.2.0 gitea.tourolle.paris/dtourolle/jellytau-builder:v1.2.0 +docker push gitea.tourolle.paris/dtourolle/jellytau-builder:v1.2.0 +``` + +3. Update the workflow to use the new tag: + +```yaml +container: + image: gitea.tourolle.paris/dtourolle/jellytau-builder:v1.2.0 +``` + +## Image Contents + +The builder image includes: + +- **Base OS**: Ubuntu 24.04 +- **Languages**: + - Rust (stable) with targets: aarch64-linux-android, armv7-linux-androideabi, x86_64-linux-android + - Node.js 20.x + - OpenJDK 17 (for Android) +- **Tools**: + - Bun package manager + - Android SDK 34 + - Android NDK 27.0.11902837 + - Build essentials (gcc, make, etc.) + - Git, curl, wget + - libssl, libclang development libraries +- **Pre-configured**: + - Rust toolchain components (rustfmt, clippy) + - Android SDK/NDK environment variables + - All paths optimized for building + +## Build Time + +First build takes ~15-20 minutes depending on internet speed (downloads Android SDK/NDK). +Subsequent builds are cached and take seconds. + +## Storage + +The built image is approximately **4-5 GB**. Ensure your registry has sufficient storage. + +## Troubleshooting + +### "Image not found" in CI +- Verify the image name matches exactly in the workflow +- Check that the image was successfully pushed: `docker push` output should show successful layers +- Ensure Gitea has access to your registry (check network/firewall) + +### Build fails with "command not found" +- The image may not have finished pushing. Wait a few moments and retry the CI job. +- Check that all layers were pushed successfully in the push output. + +### Registry authentication in CI +If your registry requires credentials in CI: +1. Create a deploy token in your registry +2. Add to Gitea secrets as `REGISTRY_USERNAME` and `REGISTRY_TOKEN` +3. Use in workflow: +```yaml +- name: Login to Registry + run: | + docker login gitea.tourolle.paris -u ${{ secrets.REGISTRY_USERNAME }} -p ${{ secrets.REGISTRY_TOKEN }} +``` + +## References + +- [Docker Build Documentation](https://docs.docker.com/build/) +- [Docker Push Documentation](https://docs.docker.com/engine/reference/commandline/push/) +- [Dockerfile Reference](https://docs.docker.com/engine/reference/builder/) diff --git a/DOCKER.md b/DOCKER.md new file mode 100644 index 0000000..6b41fc7 --- /dev/null +++ b/DOCKER.md @@ -0,0 +1,282 @@ +# Docker & CI/CD Setup for JellyTau + +This document explains how to use the Docker configuration and Gitea Act CI/CD pipeline for building and testing JellyTau. + +## Overview + +The setup includes: +- **Dockerfile.builder**: Pre-built image with all dependencies (push to your registry) +- **Dockerfile**: Multi-stage build for local testing and building +- **docker-compose.yml**: Orchestration for local development and testing +- **.gitea/workflows/build-and-test.yml**: Automated CI/CD pipeline using pre-built builder image + +### Quick Start + +**For CI/CD (Gitea Actions)**: +1. Build and push builder image (see [BUILD-BUILDER-IMAGE.md](BUILD-BUILDER-IMAGE.md)) +2. Push to master branch - workflow runs automatically +3. Check Actions tab for results and APK artifacts + +**For Local Testing**: +```bash +docker-compose run test # Run tests +docker-compose run android-build # Build APK +docker-compose run dev # Interactive shell +``` + +## Docker Usage + +### Prerequisites + +- Docker Engine 20.10+ +- Docker Compose 2.0+ (if using docker-compose) +- At least 10GB free disk space (for Android SDK and build artifacts) + +### Building the Docker Image + +```bash +# Build the complete image +docker build -t jellytau:latest . + +# Build specific target +docker build -t jellytau:test --target test . +docker build -t jellytau:android --target android-build . +``` + +### Using Docker Compose + +#### Run Tests Only +```bash +docker-compose run test +``` + +This will: +1. Install all dependencies +2. Run frontend tests (Vitest) +3. Run Rust backend tests +4. Report results + +#### Build Android APK +```bash +docker-compose run android-build +``` + +This will: +1. Run tests first (depends on test service) +2. If tests pass, build the Android APK +3. Output APK files to `src-tauri/gen/android/app/build/outputs/apk/` + +#### Interactive Development +```bash +docker-compose run dev +``` + +This starts an interactive shell with all development tools available. From here you can: +```bash +bun install +bun run build +bun test +bun run tauri android build --apk true +``` + +#### Run All Services in Sequence +```bash +docker-compose up --abort-on-container-exit +``` + +### Extracting Build Artifacts + +After a successful build, APK files are located in: +``` +src-tauri/gen/android/app/build/outputs/apk/ +``` + +Copy to your host machine: +```bash +docker cp jellytau-android-build:/app/src-tauri/gen/android/app/build/outputs/apk ./apk-output +``` + +## Gitea Act CI/CD Pipeline + +The `.gitea/workflows/build-and-test.yml` workflow automates: + +**Single Job**: Runs on every push to `master` and PRs +- Uses pre-built builder image (no setup time) +- Installs project dependencies +- Runs frontend tests (Vitest) +- Runs Rust backend tests +- Builds the frontend +- Builds the Android APK +- Uploads APK as artifact (30-day retention) + +The workflow skips markdown files to avoid unnecessary builds. + +### Workflow Triggers + +The workflow runs on: +- Push to `master` or `main` branches +- Pull requests to `master` or `main` branches +- Can be extended with: `workflow_dispatch` for manual triggers + +### Setting Up the Builder Image + +Before using the CI/CD pipeline, you must build and push the builder image: + +```bash +# Build the image +docker build -f Dockerfile.builder -t jellytau-builder:latest . + +# Tag for your registry +docker tag jellytau-builder:latest gitea.tourolle.paris/dtourolle/jellytau-builder:latest + +# Push to registry +docker push gitea.tourolle.paris/dtourolle/jellytau-builder:latest +``` + +See [BUILD-BUILDER-IMAGE.md](BUILD-BUILDER-IMAGE.md) for detailed instructions. + +### Setting Up Gitea Act + +1. **Ensure builder image is pushed** (see above) + +2. **Push to Gitea repository**: + The workflow will automatically trigger on push to `master` or pull requests + +3. **View workflow runs in Gitea UI**: + - Navigate to your repository + - Go to Actions tab + - Click on workflow runs to see logs + +4. **Test locally** (optional): + ```bash + # Install act if needed + curl https://gitea.com/actions/setup-act/releases/download/v0.25.0/act-0.25.0-linux-x86_64.tar.gz | tar xz + + # Run locally (requires builder image to be available) + ./act push --file .gitea/workflows/build-and-test.yml + ``` + +### Customizing the Workflow + +#### Modify Build Triggers +Edit `.gitea/workflows/build-and-test.yml` to change when builds run: + +```yaml +on: + push: + branches: + - master + - develop # Add more branches + paths: + - 'src/**' # Only run if src/ changes + - 'src-tauri/**' # Only run if Rust code changes +``` + +#### Add Notifications +Add Slack, Discord, or email notifications on build completion: + +```yaml +- name: Notify on success + if: success() + run: | + curl -X POST https://slack-webhook-url... +``` + +#### Customize APK Upload +Modify artifact retention or add to cloud storage: + +```yaml +- name: Upload APK to S3 + uses: actions/s3-sync@v1 + with: + aws_access_key_id: ${{ secrets.AWS_ACCESS_KEY }} + aws_secret_access_key: ${{ secrets.AWS_SECRET_KEY }} + aws_bucket: my-apk-bucket + source_dir: src-tauri/gen/android/app/build/outputs/apk/ +``` + +## Environment Setup in CI + +### Secret Variables +To use secrets in the workflow, set them in Gitea: + +1. Go to Repository Settings → Secrets +2. Add secrets like: + - `AWS_ACCESS_KEY` for S3 uploads + - `SLACK_WEBHOOK_URL` for notifications + - `GITHUB_TOKEN` for releases (pre-configured) + +## Troubleshooting + +### Out of Memory During Build +Android builds are memory-intensive. If you get OOM errors: + +```bash +# Limit memory in docker-compose +services: + android-build: + deploy: + resources: + limits: + memory: 6G +``` + +Or increase Docker's memory allocation in Docker Desktop settings. + +### Android SDK Download Timeout +If downloads timeout, increase timeout or download manually: + +```bash +# In container, with longer timeout +timeout 600 sdkmanager --sdk_root=$ANDROID_HOME ... +``` + +### Rust Compilation Errors +Make sure Rust is updated: + +```bash +rustup update +rustup target add aarch64-linux-android armv7-linux-androideabi x86_64-linux-android +``` + +### Cache Issues +Clear Docker cache and rebuild: + +```bash +docker-compose down -v # Remove volumes +docker system prune # Clean up dangling images +docker-compose up --build +``` + +## Performance Tips + +1. **Cache Reuse**: Both Docker and Gitea Act cache dependencies across runs +2. **Parallel Steps**: The workflow runs frontend and Rust tests in series; consider parallelizing for faster CI +3. **Incremental Builds**: Rust and Node caches persist between runs +4. **Docker Buildkit**: Enable for faster builds: + ```bash + DOCKER_BUILDKIT=1 docker build . + ``` + +## Security Considerations + +- Dockerfile uses `ubuntu:24.04` base image from official Docker Hub +- NDK is downloaded from official Google servers (verified via HTTPS) +- No credentials are stored in the Dockerfile +- Use Gitea Secrets for sensitive values (API keys, tokens, etc.) +- Lock dependency versions in `Cargo.toml` and `package.json` + +## Next Steps + +1. Test locally with `docker-compose up` +2. Push to your Gitea repository +3. Monitor workflow runs in the Actions tab +4. Configure secrets in repository settings for production builds +5. Set up artifact retention policies (currently 30 days) + +## References + +- [Gitea Actions Documentation](https://docs.gitea.io/en-us/actions/) +- [Docker Multi-stage Builds](https://docs.docker.com/build/building/multi-stage/) +- [Android Build Tools](https://developer.android.com/studio/command-line) +- [Tauri Android Guide](https://tauri.app/v1/guides/building/android) diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..62dbe8a --- /dev/null +++ b/Dockerfile @@ -0,0 +1,107 @@ +# Multi-stage build for JellyTau - Tauri Jellyfin client +FROM ubuntu:24.04 AS builder + +ENV DEBIAN_FRONTEND=noninteractive \ + ANDROID_HOME=/opt/android-sdk \ + NDK_VERSION=27.0.11902837 \ + SDK_VERSION=34 \ + RUST_BACKTRACE=1 + +# Install system dependencies +RUN apt-get update && apt-get install -y --no-install-recommends \ + # Build essentials + build-essential \ + curl \ + wget \ + git \ + ca-certificates \ + # Node.js (for Bun) + nodejs=20.* \ + npm \ + # Rust toolchain + rustc \ + cargo \ + # JDK for Android + openjdk-17-jdk-headless \ + # Android build tools + android-sdk-platform-tools \ + # Additional development tools + pkg-config \ + libssl-dev \ + libclang-dev \ + llvm-dev \ + && rm -rf /var/lib/apt/lists/* + +# Install Bun +RUN curl -fsSL https://bun.sh/install | bash && \ + ln -s /root/.bun/bin/bun /usr/local/bin/bun + +# Setup Rust for Android targets +RUN rustup update && \ + rustup target add aarch64-linux-android && \ + rustup target add armv7-linux-androideabi && \ + rustup target add x86_64-linux-android + +# Setup Android SDK +RUN mkdir -p $ANDROID_HOME && \ + mkdir -p /root/.android && \ + echo '### User Sources for `android` cmd line tool ###' > /root/.android/repositories.cfg && \ + echo 'count=0' >> /root/.android/repositories.cfg + +# Download and setup Android Command Line Tools +RUN wget -q https://dl.google.com/android/repository/commandlinetools-linux-11076708_latest.zip -O /tmp/cmdline-tools.zip && \ + unzip -q /tmp/cmdline-tools.zip -d $ANDROID_HOME && \ + rm /tmp/cmdline-tools.zip && \ + mkdir -p $ANDROID_HOME/cmdline-tools/latest && \ + mv $ANDROID_HOME/cmdline-tools/* $ANDROID_HOME/cmdline-tools/latest/ 2>/dev/null || true + +# Setup Android SDK components +RUN $ANDROID_HOME/cmdline-tools/latest/bin/sdkmanager --sdk_root=$ANDROID_HOME \ + "platforms;android-$SDK_VERSION" \ + "build-tools;34.0.0" \ + "ndk;$NDK_VERSION" \ + --channel=0 2>&1 | grep -v "Warning" || true + +# Set NDK environment variable +ENV NDK_HOME=$ANDROID_HOME/ndk/$NDK_VERSION + +# Create working directory +WORKDIR /app + +# Copy project files +COPY . . + +# Install Node.js dependencies +RUN bun install + +# Install Rust dependencies +RUN cd src-tauri && cargo fetch && cd .. + +# Build stage - Tests +FROM builder AS test +WORKDIR /app +RUN echo "Running tests..." && \ + bun run test && \ + cd src-tauri && cargo test && cd .. && \ + echo "All tests passed!" + +# Build stage - APK +FROM builder AS android-build +WORKDIR /app +RUN cd src-tauri && cargo fetch && cd .. && \ + echo "Building Android APK..." && \ + bun run build && \ + bun run tauri android build --apk true && \ + echo "APK build complete!" + +# Final output stage +FROM ubuntu:24.04 AS final +RUN apt-get update && apt-get install -y --no-install-recommends \ + android-sdk-platform-tools \ + && rm -rf /var/lib/apt/lists/* + +WORKDIR /app +COPY --from=android-build /app/src-tauri/gen/android/app/build/outputs/apk /app/apk + +VOLUME ["/app/apk"] +CMD ["/bin/bash", "-c", "echo 'APK files are available in /app/apk' && ls -lh /app/apk/"] diff --git a/Dockerfile.builder b/Dockerfile.builder new file mode 100644 index 0000000..1b5d4e0 --- /dev/null +++ b/Dockerfile.builder @@ -0,0 +1,68 @@ +# JellyTau Builder Image +# Pre-built image with all dependencies for building and testing +# Push to your registry: docker build -f Dockerfile.builder -t gitea.tourolle.paris/dtourolle/jellytau-builder:latest . + +FROM ubuntu:24.04 + +ENV DEBIAN_FRONTEND=noninteractive \ + ANDROID_HOME=/opt/android-sdk \ + NDK_VERSION=27.0.11902837 \ + SDK_VERSION=34 \ + RUST_BACKTRACE=1 \ + PATH="/root/.bun/bin:/root/.cargo/bin:$PATH" + +# Install system dependencies +RUN apt-get update && apt-get install -y --no-install-recommends \ + build-essential \ + curl \ + wget \ + git \ + ca-certificates \ + nodejs \ + npm \ + rustc \ + cargo \ + openjdk-17-jdk-headless \ + pkg-config \ + libssl-dev \ + libclang-dev \ + llvm-dev \ + && rm -rf /var/lib/apt/lists/* + +# Install Bun +RUN curl -fsSL https://bun.sh/install | bash && \ + ln -s /root/.bun/bin/bun /usr/local/bin/bun + +# Setup Rust for Android targets +RUN rustup update && \ + rustup target add aarch64-linux-android && \ + rustup target add armv7-linux-androideabi && \ + rustup target add x86_64-linux-android && \ + rustup component add rustfmt clippy + +# Setup Android SDK +RUN mkdir -p $ANDROID_HOME && \ + mkdir -p /root/.android && \ + echo '### User Sources for `android` cmd line tool ###' > /root/.android/repositories.cfg && \ + echo 'count=0' >> /root/.android/repositories.cfg + +# Download and setup Android Command Line Tools +RUN wget -q https://dl.google.com/android/repository/commandlinetools-linux-11076708_latest.zip -O /tmp/cmdline-tools.zip && \ + unzip -q /tmp/cmdline-tools.zip -d $ANDROID_HOME && \ + rm /tmp/cmdline-tools.zip && \ + mkdir -p $ANDROID_HOME/cmdline-tools/latest && \ + mv $ANDROID_HOME/cmdline-tools/* $ANDROID_HOME/cmdline-tools/latest/ 2>/dev/null || true + +# Install Android SDK components +RUN $ANDROID_HOME/cmdline-tools/latest/bin/sdkmanager --sdk_root=$ANDROID_HOME \ + "platforms;android-$SDK_VERSION" \ + "build-tools;34.0.0" \ + "ndk;$NDK_VERSION" \ + --channel=0 2>&1 | grep -v "Warning" || true + +# Set NDK environment variable +ENV NDK_HOME=$ANDROID_HOME/ndk/$NDK_VERSION + +WORKDIR /app + +ENTRYPOINT ["/bin/bash"] diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..ff6f71a --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,62 @@ +version: '3.8' + +services: + # Test service - runs tests only + test: + build: + context: . + dockerfile: Dockerfile + target: test + container_name: jellytau-test + volumes: + - .:/app + environment: + - RUST_BACKTRACE=1 + command: bash -c "bun test && cd src-tauri && cargo test && cd .. && echo 'All tests passed!'" + + # Android build service - builds APK after tests pass + android-build: + build: + context: . + dockerfile: Dockerfile + target: android-build + container_name: jellytau-android-build + volumes: + - .:/app + - android-cache:/root/.cargo + - android-bun-cache:/root/.bun + environment: + - RUST_BACKTRACE=1 + - ANDROID_HOME=/opt/android-sdk + depends_on: + - test + ports: + - "5172:5172" # In case you want to run dev server + + # Development container - for interactive development + dev: + build: + context: . + dockerfile: Dockerfile + target: builder + container_name: jellytau-dev + volumes: + - .:/app + - cargo-cache:/root/.cargo + - bun-cache:/root/.bun + - node-modules:/app/node_modules + environment: + - RUST_BACKTRACE=1 + - ANDROID_HOME=/opt/android-sdk + - NDK_HOME=/opt/android-sdk/ndk/27.0.11902837 + working_dir: /app + stdin_open: true + tty: true + command: /bin/bash + +volumes: + cargo-cache: + bun-cache: + android-cache: + android-bun-cache: + node-modules: diff --git a/scripts/build-builder-image.sh b/scripts/build-builder-image.sh new file mode 100755 index 0000000..697b008 --- /dev/null +++ b/scripts/build-builder-image.sh @@ -0,0 +1,44 @@ +#!/bin/bash +# Build and push the JellyTau builder Docker image to your registry + +set -e + +# Configuration +REGISTRY_HOST="${REGISTRY_HOST:-gitea.tourolle.paris}" +REGISTRY_USER="${REGISTRY_USER:-dtourolle}" +IMAGE_NAME="jellytau-builder" +IMAGE_TAG="${1:-latest}" +FULL_IMAGE_NAME="${REGISTRY_HOST}/${REGISTRY_USER}/${IMAGE_NAME}:${IMAGE_TAG}" + +echo "🐳 Building JellyTau Builder Image" +echo "==================================" +echo "Registry: $REGISTRY_HOST" +echo "User: $REGISTRY_USER" +echo "Image: $FULL_IMAGE_NAME" +echo "" + +# Step 1: Build locally +echo "🔨 Building Docker image locally..." +docker build -f Dockerfile.builder -t ${IMAGE_NAME}:${IMAGE_TAG} . + +# Step 2: Tag for registry +echo "🏷️ Tagging for registry..." +docker tag ${IMAGE_NAME}:${IMAGE_TAG} ${FULL_IMAGE_NAME} + +# Step 3: Login to registry (if not already logged in) +echo "🔐 Checking registry authentication..." +if ! docker info | grep -q "Username"; then + echo "Not authenticated to Docker. Logging in to ${REGISTRY_HOST}..." + docker login ${REGISTRY_HOST} +fi + +# Step 4: Push to registry +echo "📤 Pushing image to registry..." +docker push ${FULL_IMAGE_NAME} + +echo "" +echo "✅ Successfully built and pushed: ${FULL_IMAGE_NAME}" +echo "" +echo "Update your workflow to use:" +echo " container:" +echo " image: ${FULL_IMAGE_NAME}" diff --git a/src/lib/components/library/GenericMediaListPage.svelte b/src/lib/components/library/GenericMediaListPage.svelte index f148efd..0aa087b 100644 --- a/src/lib/components/library/GenericMediaListPage.svelte +++ b/src/lib/components/library/GenericMediaListPage.svelte @@ -125,16 +125,19 @@ function handleItemClick(item: MediaItem) { // Navigate to detail page for browseable items - goto(`/library/${item.id}`); + console.log('Item clicked:', item.id, item.name); + goto(`/library/${item.id}`).catch(err => { + console.error('Navigation failed:', err); + }); } function handleTrackClick(track: MediaItem, _index: number) { // For track lists, navigate to the track's album if available, otherwise detail page - if (track.albumId) { - goto(`/library/${track.albumId}`); - } else { - goto(`/library/${track.id}`); - } + console.log('Track clicked:', track.id, track.name); + const targetId = track.albumId || track.id; + goto(`/library/${targetId}`).catch(err => { + console.error('Navigation failed:', err); + }); } diff --git a/src/lib/components/library/LibraryListView.svelte b/src/lib/components/library/LibraryListView.svelte index 3d0bdf7..76920f2 100644 --- a/src/lib/components/library/LibraryListView.svelte +++ b/src/lib/components/library/LibraryListView.svelte @@ -21,7 +21,7 @@ const repo = auth.getRepository(); const tag = "primaryImageTag" in item ? item.primaryImageTag : ("imageTag" in item ? item.imageTag : undefined); return repo.getImageUrl(item.id, "Primary", { - maxWidth: 80, + maxWidth: 120, tag, }); } catch { @@ -84,8 +84,15 @@ + {#if idx < track.artistItems.length - 1} , {/if} @@ -279,13 +288,13 @@ {#if showAlbum}
{#if track.albumId} - + {:else} {track.albumName || "-"} {/if} @@ -333,9 +342,10 @@ + {#if idx < track.artistItems.length - 1} , {/if} @@ -381,26 +391,26 @@ {/if} {#if track.albumId} - + {:else} {track.albumName || "-"} {/if} {:else if showArtist} {#if track.artistItems && track.artistItems.length > 0} {#each track.artistItems as artist, idx} - + {#if idx < track.artistItems.length - 1} , {/if} @@ -410,13 +420,13 @@ {/if} {:else if showAlbum} {#if track.albumId} - + {:else} {track.albumName || "-"} {/if} diff --git a/src/routes/library/+page.svelte b/src/routes/library/+page.svelte index 2279574..801f639 100644 --- a/src/routes/library/+page.svelte +++ b/src/routes/library/+page.svelte @@ -43,17 +43,21 @@ }); async function handleLibraryClick(lib: Library) { - // Route to dedicated music library page - if (lib.collectionType === "music") { - library.setCurrentLibrary(lib); - goto("/library/music"); - return; - } + try { + // Route to dedicated music library page + if (lib.collectionType === "music") { + library.setCurrentLibrary(lib); + await goto("/library/music"); + return; + } - // For other library types, load items normally - library.setCurrentLibrary(lib); - library.clearGenres(); - await library.loadItems(lib.id); + // For other library types, load items normally + library.setCurrentLibrary(lib); + library.clearGenres(); + await library.loadItems(lib.id); + } catch (error) { + console.error("Navigation error:", error); + } } async function handleGenreFilterChange() { @@ -64,35 +68,39 @@ } } - function handleItemClick(item: MediaItem | Library) { - if ("type" in item) { - // It's a MediaItem - const mediaItem = item as MediaItem; - switch (mediaItem.type) { - case "Series": - case "Movie": - case "MusicAlbum": - case "MusicArtist": - case "Folder": - case "CollectionFolder": - case "Playlist": - case "Channel": - case "ChannelFolderItem": - // Navigate to detail view - goto(`/library/${mediaItem.id}`); - break; - case "Episode": - // Episodes play directly - goto(`/player/${mediaItem.id}`); - break; - default: - // For other items, try detail page first - goto(`/library/${mediaItem.id}`); - break; + async function handleItemClick(item: MediaItem | Library) { + try { + if ("type" in item) { + // It's a MediaItem + const mediaItem = item as MediaItem; + switch (mediaItem.type) { + case "Series": + case "Movie": + case "MusicAlbum": + case "MusicArtist": + case "Folder": + case "CollectionFolder": + case "Playlist": + case "Channel": + case "ChannelFolderItem": + // Navigate to detail view + await goto(`/library/${mediaItem.id}`); + break; + case "Episode": + // Episodes play directly + await goto(`/player/${mediaItem.id}`); + break; + default: + // For other items, try detail page first + await goto(`/library/${mediaItem.id}`); + break; + } + } else { + // It's a Library + await handleLibraryClick(item as Library); } - } else { - // It's a Library - handleLibraryClick(item as Library); + } catch (error) { + console.error("Navigation error:", error); } } @@ -180,11 +188,11 @@

No libraries found

{:else} -
+
{#each $libraries as lib (lib.id)} handleLibraryClick(lib)} /> {/each} diff --git a/src/routes/library/music/+page.svelte b/src/routes/library/music/+page.svelte index c6b832d..37d289c 100644 --- a/src/routes/library/music/+page.svelte +++ b/src/routes/library/music/+page.svelte @@ -1,6 +1,4 @@
@@ -59,27 +53,27 @@

Music Library

Choose a category to browse

- +
{#each categories as category (category.id)} -
- + {/each}