Compare commits

..
1 Commits
Author SHA1 Message Date
gitea-actions 7a99751cdf docs: publish site from a9463246 2026-08-23 17:30:05 +00:00
2088 changed files with 171462 additions and 111613 deletions
-18
View File
@@ -1,18 +0,0 @@
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
-124
View File
@@ -1,124 +0,0 @@
name: '🏗️ Build and Test JellyTau'
on:
push:
branches:
- master
paths-ignore:
- '**/*.md'
pull_request:
branches:
- master
paths-ignore:
- '**/*.md'
workflow_dispatch:
jobs:
test:
name: Run Tests
runs-on: linux/amd64
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-host-${{ hashFiles('**/Cargo.lock') }}
restore-keys: |
${{ runner.os }}-cargo-host-
- 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
# Tripwire for domain-taxonomy leaks into the presentation layer (a
# multi-type includeItemTypes query defining a category in the frontend).
# See scripts/check-frontend-boundary.sh and
# docs/specs/scoped-search-boundary.md.
- name: Check frontend/backend boundary
run: bash scripts/check-frontend-boundary.sh
- name: Run frontend tests
run: |
bunx svelte-kit sync
bun run test
- name: Run Rust tests
run: |
cd src-tauri
cargo test
cd ..
# Fast per-commit Android compile check. This does NOT build a shippable APK:
# the full signed release APK is built only on tag pushes by build-release.yml
# (which runs sync-android-sources.sh + signing). Running the full bundle here
# too would duplicate a ~15min build and, without the sync step, produced an
# unsigned APK missing our custom sources/icons/proguard rules anyway.
# `cargo check` for the Android target (~1min) catches Android-specific Rust
# breakage without linking, bundling, or signing.
android-check:
name: Android Compile Check
runs-on: linux/amd64
needs: test
container:
image: gitea.tourolle.paris/dtourolle/jellytau-builder:latest
env:
ANDROID_HOME: /opt/android-sdk
ANDROID_SDK_ROOT: /opt/android-sdk
NDK_HOME: /opt/android-sdk/ndk/27.0.11902837
ANDROID_NDK_HOME: /opt/android-sdk/ndk/27.0.11902837
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-android-${{ hashFiles('**/Cargo.lock') }}
restore-keys: |
${{ runner.os }}-cargo-android-
- 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: Cargo check (aarch64-linux-android)
run: |
TC="$NDK_HOME/toolchains/llvm/prebuilt/linux-x86_64/bin"
export CARGO_TARGET_AARCH64_LINUX_ANDROID_LINKER="$TC/aarch64-linux-android24-clang"
export CC_aarch64_linux_android="$TC/aarch64-linux-android24-clang"
export AR_aarch64_linux_android="$TC/llvm-ar"
cd src-tauri
cargo check --target aarch64-linux-android --lib
-436
View File
@@ -1,436 +0,0 @@
name: Build & Release
on:
push:
tags:
- 'v*'
workflow_dispatch:
inputs:
version:
description: 'Version to build (e.g., v1.0.0)'
required: false
env:
RUST_BACKTRACE: 1
CARGO_TERM_COLOR: always
jobs:
test:
name: Run Tests
runs-on: linux/amd64
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-host-${{ hashFiles('**/Cargo.lock') }}
restore-keys: |
${{ runner.os }}-cargo-host-
- 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: |
bunx svelte-kit sync
bun run test --run
continue-on-error: false
- name: Run Rust tests
run: bun run test:rust
continue-on-error: false
- name: Check TypeScript
run: bun run check
continue-on-error: false
build-linux:
name: Build Linux
runs-on: linux/amd64
needs: test
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-host-${{ hashFiles('**/Cargo.lock') }}
restore-keys: |
${{ runner.os }}-cargo-host-
- 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: Build for Linux
run: bun run tauri build
env:
TAURI_SKIP_UPDATER: true
- name: Prepare Linux artifacts
run: |
mkdir -p dist/linux
# Copy AppImage
if [ -f "src-tauri/target/release/bundle/appimage/jellytau_"*.AppImage ]; then
cp src-tauri/target/release/bundle/appimage/jellytau_*.AppImage dist/linux/
fi
# Copy .deb if built
if [ -f "src-tauri/target/release/bundle/deb/jellytau_"*.deb ]; then
cp src-tauri/target/release/bundle/deb/jellytau_*.deb dist/linux/
fi
ls -lah dist/linux/
- name: Upload Linux build artifact
uses: actions/upload-artifact@v3
with:
name: jellytau-linux
path: dist/linux/
retention-days: 30
build-windows:
name: Build Windows
runs-on: linux/amd64
needs: test
# Cross-compiled from Linux via the official Tauri path (MSVC + cargo-xwin),
# baked into the builder image. No toolchain installs here — the image has
# cargo-xwin, clang/clang-cl, lld, llvm, nsis and the msvc target.
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
~/.cache/cargo-xwin
src-tauri/target
key: ${{ runner.os }}-cargo-windows-${{ hashFiles('**/Cargo.lock') }}
restore-keys: |
${{ runner.os }}-cargo-windows-
- 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: Set app version from tag
run: |
# On a tag build the tag is the single source of truth for the version.
if echo "$GITHUB_REF" | grep -q '^refs/tags/v'; then
VERSION="${GITHUB_REF#refs/tags/v}"
echo "Setting version to $VERSION"
sed -i "s/\"version\": \"[^\"]*\"/\"version\": \"$VERSION\"/" src-tauri/tauri.conf.json
fi
grep '"version"' src-tauri/tauri.conf.json
- name: Build Windows (NSIS installer + exe)
run: OUTPUT_DIR="$PWD/dist/windows" WIN_BUNDLES=nsis ./scripts/build-windows-cross.sh
- name: List Windows artifacts
run: ls -lah dist/windows/
- name: Upload Windows build artifact
uses: actions/upload-artifact@v3
with:
name: jellytau-windows
path: dist/windows/
retention-days: 30
build-android:
name: Build Android
runs-on: linux/amd64
needs: test
container:
image: gitea.tourolle.paris/dtourolle/jellytau-builder:latest
env:
ANDROID_HOME: /opt/android-sdk
ANDROID_SDK_ROOT: /opt/android-sdk
ANDROID_NDK_HOME: /opt/android-sdk/ndk/27.0.11902837
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-android-${{ hashFiles('**/Cargo.lock') }}
restore-keys: |
${{ runner.os }}-cargo-android-
- 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: Set app version from tag
run: |
# On a tag build, the tag is the single source of truth for the
# version name. On non-tag runs keep whatever is in tauri.conf.json.
if echo "$GITHUB_REF" | grep -q '^refs/tags/v'; then
VERSION="${GITHUB_REF#refs/tags/v}"
echo "Setting version to $VERSION"
sed -i "s/\"version\": \"[^\"]*\"/\"version\": \"$VERSION\"/" src-tauri/tauri.conf.json
fi
grep '"version"' src-tauri/tauri.conf.json
- name: Initialize Android project
run: bun run tauri android init
- name: Pin a monotonic Android versionCode
run: |
# `tauri android init` autogenerates src-tauri/gen/android/app/tauri.properties
# with a versionCode derived from the semver (e.g. 0.0.15 -> 15). That
# number is (a) tiny and (b) NOT monotonic across our history: earlier
# local/dev builds shipped versionCode 1000 (from a 0.1.0 config), so a
# plain 15 would be a *downgrade* and Android would refuse the update.
#
# Derive an explicit code that is both monotonic in semver order and
# always above the 1000 floor already in the field:
# code = 1000 + major*10000 + minor*100 + patch
# e.g. 0.0.14 -> 1014, 0.0.15 -> 1015, 0.1.0 -> 1100, 1.0.0 -> 11000.
# POSIX sh only (the runner uses dash): no here-strings, no \s in sed.
PROPS="src-tauri/gen/android/app/tauri.properties"
VERSION=$(grep '"version"' src-tauri/tauri.conf.json | head -1 | sed -E 's/.*"version"[[:space:]]*:[[:space:]]*"([^"]+)".*/\1/')
MAJ=$(echo "$VERSION" | cut -d. -f1)
MIN=$(echo "$VERSION" | cut -d. -f2)
PAT=$(echo "$VERSION" | cut -d. -f3)
# Guard against a malformed/missing component so we never emit code 0.
: "${MAJ:=0}" "${MIN:=0}" "${PAT:=0}"
CODE=$(( 1000 + MAJ*10000 + MIN*100 + PAT ))
echo "version=$VERSION -> versionCode=$CODE"
if grep -q '^tauri.android.versionCode=' "$PROPS"; then
sed -i "s/^tauri.android.versionCode=.*/tauri.android.versionCode=$CODE/" "$PROPS"
else
echo "tauri.android.versionCode=$CODE" >> "$PROPS"
fi
cat "$PROPS"
- name: Sync custom Android sources & gradle config
run: ./scripts/sync-android-sources.sh
- name: Write signing keystore
run: |
echo "${{ secrets.ANDROID_KEYSTORE_BASE64 }}" | base64 -d > "$RUNNER_TEMP/jellytau-release.jks"
cat > src-tauri/gen/android/keystore.properties <<EOF
storeFile=$RUNNER_TEMP/jellytau-release.jks
storePassword=${{ secrets.ANDROID_KEYSTORE_PASSWORD }}
keyAlias=${{ secrets.ANDROID_KEY_ALIAS }}
keyPassword=${{ secrets.ANDROID_KEY_PASSWORD }}
EOF
- name: Build signed Android APK
run: bun run tauri android build --apk true --target aarch64
- name: Collect & verify signed APK
run: |
mkdir -p dist/android
APK=$(find src-tauri/gen/android/app/build/outputs/apk -name '*-release.apk' | head -1)
if [ -z "$APK" ]; then echo "❌ No release APK produced"; exit 1; fi
cp "$APK" dist/android/jellytau-release.apk
APKSIGNER=$(find "$ANDROID_SDK_ROOT/build-tools" -name apksigner | sort -V | tail -1)
echo "🔏 Verifying signature with $APKSIGNER"
"$APKSIGNER" verify --print-certs dist/android/jellytau-release.apk
ls -lah dist/android/
- name: Upload Android build artifact
uses: actions/upload-artifact@v3
with:
name: jellytau-android
path: dist/android/
retention-days: 30
create-release:
name: Create Release
runs-on: linux/amd64
needs: [build-linux, build-windows, build-android]
if: startsWith(github.ref, 'refs/tags/v')
container:
image: gitea.tourolle.paris/dtourolle/jellytau-builder:latest
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Get version from tag
id: tag_name
run: |
echo "VERSION=${GITHUB_REF#refs/tags/}" >> $GITHUB_OUTPUT
echo "RELEASE_NAME=JellyTau ${GITHUB_REF#refs/tags/}" >> $GITHUB_OUTPUT
- name: Download Linux artifacts
uses: actions/download-artifact@v3
with:
name: jellytau-linux
path: artifacts/linux/
- name: Download Windows artifacts
uses: actions/download-artifact@v3
with:
name: jellytau-windows
path: artifacts/windows/
- name: Download Android artifacts
uses: actions/download-artifact@v3
with:
name: jellytau-android
path: artifacts/android/
- name: Prepare release notes
id: release_notes
run: |
VERSION="${{ steps.tag_name.outputs.VERSION }}"
echo "## JellyTau $VERSION Release" > release_notes.md
echo "" >> release_notes.md
echo "### Downloads" >> release_notes.md
echo "" >> release_notes.md
echo "#### Linux" >> release_notes.md
echo "- **AppImage** - Run directly on most Linux distributions" >> release_notes.md
echo "- **DEB** - Install via \`sudo dpkg -i jellytau_*.deb\` (Ubuntu/Debian)" >> release_notes.md
echo "" >> release_notes.md
echo "#### Windows" >> release_notes.md
echo "- **Installer (.exe)** - Run \`jellytau_*-setup.exe\` (NSIS). Unsigned — SmartScreen may warn on first run." >> release_notes.md
echo "" >> release_notes.md
echo "#### Android" >> release_notes.md
echo "- **APK** - Install via \`adb install jellytau-release.apk\` or sideload via file manager" >> release_notes.md
echo "- **AAB** - Upload to Google Play Console or testing platforms" >> release_notes.md
echo "" >> release_notes.md
echo "### What's New" >> release_notes.md
echo "" >> release_notes.md
echo "See [CHANGELOG.md](CHANGELOG.md) for detailed changes." >> release_notes.md
echo "" >> release_notes.md
echo "### Installation" >> release_notes.md
echo "" >> release_notes.md
echo "#### Linux (AppImage)" >> release_notes.md
echo "\`\`\`bash" >> release_notes.md
echo "chmod +x jellytau_*.AppImage" >> release_notes.md
echo "./jellytau_*.AppImage" >> release_notes.md
echo "\`\`\`" >> release_notes.md
echo "" >> release_notes.md
echo "#### Linux (DEB)" >> release_notes.md
echo "\`\`\`bash" >> release_notes.md
echo "sudo dpkg -i jellytau_*.deb" >> release_notes.md
echo "jellytau" >> release_notes.md
echo "\`\`\`" >> release_notes.md
echo "" >> release_notes.md
echo "#### Android" >> release_notes.md
echo "- Sideload: Download APK and install via file manager or ADB" >> release_notes.md
echo "- Play Store: Coming soon" >> release_notes.md
echo "" >> release_notes.md
echo "### Known Issues" >> release_notes.md
echo "" >> release_notes.md
echo "See [GitHub Issues](../../issues) for reported bugs." >> release_notes.md
echo "" >> release_notes.md
echo "### Requirements" >> release_notes.md
echo "" >> release_notes.md
echo "**Linux:**" >> release_notes.md
echo "- 64-bit Linux system" >> release_notes.md
echo "- GLIBC 2.29+" >> release_notes.md
echo "" >> release_notes.md
echo "**Android:**" >> release_notes.md
echo "- Android 8.0 or higher" >> release_notes.md
echo "- 50MB free storage" >> release_notes.md
echo "" >> release_notes.md
echo "---" >> release_notes.md
echo "Built with Tauri, SvelteKit, and Rust" >> release_notes.md
- name: Publish Gitea release & upload assets
env:
# GITEA_TOKEN (a PAT) is preferred; falls back to the auto-provided token.
GITEA_TOKEN: ${{ secrets.GITEA_TOKEN }}
AUTO_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
set -e
command -v jq >/dev/null || { echo "❌ jq is required on the runner"; exit 1; }
VERSION="${{ steps.tag_name.outputs.VERSION }}"
API="${GITHUB_SERVER_URL}/api/v1"
REPO="${GITHUB_REPOSITORY}"
TOKEN="${GITEA_TOKEN:-$AUTO_TOKEN}"
case "$VERSION" in *rc*|*beta*|*alpha*) PRE=true;; *) PRE=false;; esac
PAYLOAD=$(jq -n \
--arg tag "$VERSION" \
--arg name "JellyTau $VERSION" \
--rawfile body release_notes.md \
--argjson pre "$PRE" \
'{tag_name:$tag, name:$name, body:$body, draft:false, prerelease:$pre}')
echo "📦 Creating release $VERSION on $REPO"
# -f drops on HTTP error; capture status so an existing release (409) is handled gracefully.
HTTP=$(curl -sS -o resp.json -w '%{http_code}' -X POST "$API/repos/$REPO/releases" \
-H "Authorization: token $TOKEN" \
-H "Content-Type: application/json" \
-d "$PAYLOAD")
if [ "$HTTP" = "201" ]; then
RELEASE_ID=$(jq -r '.id' resp.json)
elif [ "$HTTP" = "409" ]; then
echo "️ Release $VERSION already exists; fetching its id to upload assets"
RELEASE_ID=$(curl -fsS "$API/repos/$REPO/releases/tags/$VERSION" \
-H "Authorization: token $TOKEN" | jq -r '.id')
else
echo "❌ Failed to create release (HTTP $HTTP):"; cat resp.json; exit 1
fi
echo "Release id=$RELEASE_ID"
for f in artifacts/android/* artifacts/linux/* artifacts/windows/*; do
[ -f "$f" ] || continue
echo "⬆️ Uploading $(basename "$f")"
curl -fsS -X POST \
"$API/repos/$REPO/releases/$RELEASE_ID/assets?name=$(basename "$f")" \
-H "Authorization: token $TOKEN" \
-F "attachment=@$f" >/dev/null
done
echo "✅ Release $VERSION published with assets"
-124
View File
@@ -1,124 +0,0 @@
name: Publish Documentation
# Renders the markdown docs (docs/*.md) into an mdBook site, builds the Rust
# API reference with cargo doc, and force-pushes the combined output to the
# orphan `gitea-pages` branch that the Gitea Pages server serves.
#
# The published matrix is regenerated during the build, so it is never stale.
on:
push:
branches:
- master
concurrency:
# Only one docs publish at a time; a newer push supersedes an in-flight run.
group: publish-docs
cancel-in-progress: true
jobs:
publish-docs:
name: Build & publish docs to gitea-pages
runs-on: linux/amd64
container:
image: gitea.tourolle.paris/dtourolle/jellytau-builder:latest
steps:
- name: Checkout code
uses: actions/checkout@v4
with:
fetch-depth: 0
# bun is baked into jellytau-builder (see Dockerfile.builder); no setup-bun
# action needed — fetching it stalls on this Gitea runner.
- name: Install dependencies
run: bun install
- name: Install mdBook
run: |
set -e
MDBOOK_VERSION=v0.4.40
URL="https://github.com/rust-lang/mdBook/releases/download/${MDBOOK_VERSION}/mdbook-${MDBOOK_VERSION}-x86_64-unknown-linux-gnu.tar.gz"
echo "⬇️ Downloading mdBook ${MDBOOK_VERSION}"
curl -fsSL "$URL" | tar -xz -C /usr/local/bin
mdbook --version
- name: Regenerate traceability matrix (keep published copy current)
run: bun run traces:markdown
- name: Assemble mdBook sources
run: |
set -e
# mdBook's src is docs/. Drop in the SUMMARY and the generated
# intro + API redirect pages (build artifacts, not committed).
cp docs-site/SUMMARY.md docs/SUMMARY.md
cat > docs/README.md <<'EOF'
# JellyTau Documentation
Cross-platform Jellyfin client — business logic in a Rust backend,
SvelteKit + TypeScript frontend, talking over Tauri v2 IPC.
- **[Requirements Specification](requirements.md)** — user, integration, and development requirements.
- **[Traceability Matrix](traceability.md)** — generated map from requirements to code (regenerated on every publish).
- **[Architecture](architecture/README.md)** — backend, frontend, data flow, platform backends.
- **[Rust API Reference](api/index.html)** — rustdoc for the `src-tauri` backend.
_This site is published automatically from `master` by the `publish-docs` CI job._
EOF
cat > docs/api-redirect.md <<'EOF'
# Rust API Reference
The full backend API reference is generated by `cargo doc` (rustdoc).
👉 **[Open the Rust API Reference](api/index.html)**
EOF
- name: Build mdBook site
run: mdbook build docs-site --dest-dir "$GITHUB_WORKSPACE/site"
- name: Build Rust API docs (cargo doc)
working-directory: src-tauri
# --no-deps keeps it to our own crate (fast, focused); document private
# items so internal modules/commands appear.
run: |
cargo doc --no-deps --document-private-items
# The backend modules/commands live in the LIB crate (jellytau_lib);
# the bin crate (jellytau) is a near-empty shim. Land on the lib.
echo '<meta http-equiv="refresh" content="0; url=jellytau_lib/index.html">' \
> target/doc/index.html
- name: Assemble published output
run: |
set -e
mkdir -p "$GITHUB_WORKSPACE/site/api"
cp -r src-tauri/target/doc/. "$GITHUB_WORKSPACE/site/api/"
# Disable Jekyll processing on the pages branch.
touch "$GITHUB_WORKSPACE/site/.nojekyll"
ls -la "$GITHUB_WORKSPACE/site"
- name: Push to gitea-pages branch
env:
# PAT preferred; falls back to the auto-provided token (same pattern
# as build-release.yml).
GITEA_TOKEN: ${{ secrets.GITEA_TOKEN }}
AUTO_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
set -e
TOKEN="${GITEA_TOKEN:-$AUTO_TOKEN}"
REPO="${GITHUB_REPOSITORY}"
HOST="$(echo "$GITHUB_SERVER_URL" | sed -E 's#^https?://##')"
REMOTE="https://oauth2:${TOKEN}@${HOST}/${REPO}.git"
cd "$GITHUB_WORKSPACE/site"
git init -q
git config user.name "gitea-actions"
git config user.email "actions@gitea.tourolle.paris"
git checkout -q -b gitea-pages
git add -A
# POSIX sh has no ${VAR::N} substring expansion — cut instead.
SHORT_SHA="$(printf '%s' "$GITHUB_SHA" | cut -c1-8)"
git commit -q -m "docs: publish site from ${SHORT_SHA}"
echo "🚀 Force-pushing to gitea-pages"
git push -f "$REMOTE" gitea-pages
-151
View File
@@ -1,151 +0,0 @@
name: Traceability Validation
on:
push:
branches:
- master
- main
- develop
pull_request:
branches:
- master
- main
- develop
jobs:
validate-traces:
runs-on: linux/amd64
name: Check Requirement Traces
container:
image: gitea.tourolle.paris/dtourolle/jellytau-builder:latest
steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
fetch-depth: 0
# bun is baked into jellytau-builder (see Dockerfile.builder); no setup-bun
# action needed — fetching it stalls on this Gitea runner.
- name: Install dependencies
run: bun install
- name: Extract traces
run: |
echo "🔍 Extracting requirement traces..."
bun run traces:json > traces-report.json
- name: Validate traces
run: |
set -e
echo "📊 Validating requirement traceability..."
echo ""
# Parse JSON
TOTAL_TRACES=$(jq '.totalTraces' traces-report.json)
UR=$(jq '.byType.UR | length' traces-report.json)
IR=$(jq '.byType.IR | length' traces-report.json)
DR=$(jq '.byType.DR | length' traces-report.json)
JA=$(jq '.byType.JA | length' traces-report.json)
# Print coverage report
echo "✅ TRACES Found: $TOTAL_TRACES"
echo ""
echo "📋 Coverage Summary:"
echo " User Requirements (UR): $UR / 39 ($(( UR * 100 / 39 ))%)"
echo " Integration Requirements (IR): $IR / 24 ($(( IR * 100 / 24 ))%)"
echo " Development Requirements (DR): $DR / 48 ($(( DR * 100 / 48 ))%)"
echo " Jellyfin API Requirements (JA): $JA / 3 ($(( JA * 100 / 3 ))%)"
echo ""
COVERED=$((UR + IR + DR + JA))
TOTAL_REQS=114
COVERAGE=$((COVERED * 100 / TOTAL_REQS))
echo "📈 Overall Coverage: $COVERED / $TOTAL_REQS ($COVERAGE%)"
echo ""
# Check minimum threshold
MIN_THRESHOLD=50
if [ "$COVERAGE" -lt "$MIN_THRESHOLD" ]; then
echo "❌ ERROR: Coverage ($COVERAGE%) is below minimum threshold ($MIN_THRESHOLD%)"
exit 1
fi
echo "✅ Coverage is acceptable ($COVERAGE% >= $MIN_THRESHOLD%)"
- name: Check modified files
if: github.event_name == 'pull_request'
run: |
echo "🔍 Checking modified files for traces..."
echo ""
# Get changed files
CHANGED=$(git diff --name-only origin/${{ github.base_ref }}...HEAD | grep -E '\.(ts|tsx|svelte|rs)$' || echo "")
if [ -z "$CHANGED" ]; then
echo "✅ No TypeScript/Rust files changed"
exit 0
fi
echo "📝 Changed files:"
echo "$CHANGED" | sed 's/^/ /'
echo ""
# Check each file
# Pipe into the loop instead of a here-string (<<<) so this step works
# under POSIX sh/dash, not just bash. Use `case` instead of `[[ == ]]`
# for the same reason. The loop runs in a subshell (so a counter var
# wouldn't survive), so we record warnings in a temp file and count it
# afterwards.
MISSING_FILE=$(mktemp)
echo "$CHANGED" | while IFS= read -r file; do
# Skip test files
case "$file" in
*.test.*) continue ;;
esac
if [ -f "$file" ]; then
if ! grep -q "TRACES:" "$file"; then
echo "⚠️ Missing TRACES: $file"
echo "$file" >> "$MISSING_FILE"
fi
fi
done
MISSING_TRACES=$(wc -l < "$MISSING_FILE" | tr -d ' ')
rm -f "$MISSING_FILE"
if [ "$MISSING_TRACES" -gt 0 ]; then
echo ""
echo "📝 Recommendation: Add TRACES comments to new/modified code"
echo " Format: // TRACES: UR-001, UR-002 | DR-003"
echo ""
echo "💡 For more info, see: scripts/README.md"
fi
- name: Generate full report
if: always()
run: |
echo "📄 Generating full traceability report..."
bun run traces:markdown
- name: Display report summary
if: always()
run: |
echo ""
echo "📊 Full Report Generated"
echo "📁 Location: docs/traceability.md"
echo ""
head -50 docs/traceability.md || true
- name: Save artifacts
if: always()
uses: actions/upload-artifact@v3
with:
name: traceability-reports
path: |
traces-report.json
docs/traceability.md
retention-days: 30
-66
View File
@@ -1,66 +0,0 @@
# OS files
.DS_Store
Thumbs.db
# Node.js
node_modules
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
# Use bun (see packageManager in package.json); ignore other package managers' lockfiles
package-lock.json
yarn.lock
pnpm-lock.yaml
# Build output
/build
/dist
/.svelte-kit
/package
# Environment variables
.env
.env.*
!.env.example
# Testing
coverage
.nyc_output
*.lcov
# WebdriverIO E2E tests
e2e/logs/
e2e/screenshots/
wdio-*.log
# Vitest
.vitest
# Vite
vite.config.js.timestamp-*
vite.config.ts.timestamp-*
# IDE
.idea
.vscode
*.swp
*.swo
*~
# Logs
logs
*.log
# Android signing keystore (NEVER commit)
android-keystore/
# Local machine-specific Android NDK toolchain paths (do not commit)
src-tauri/.cargo/config.toml
# Docs site build artifacts (generated by the publish-docs CI job into docs/)
/docs/SUMMARY.md
/docs/README.md
/docs/api-redirect.md
/docs-site/book/
+1
View File
@@ -0,0 +1 @@
This file makes sure that Github Pages doesn't process mdBook's output.
+221
View File
File diff suppressed because one or more lines are too long
-297
View File
@@ -1,297 +0,0 @@
# JellyTau
A cross-platform Jellyfin client. Business logic lives in a Rust backend
(`src-tauri/`); a SvelteKit + TypeScript frontend (`src/`) handles presentation
and talks to it over Tauri v2 IPC. Targets **Linux** (libmpv, WebKitGTK HTML5
`<video>` for transcoded playback) and **Android** (ExoPlayer).
Package manager is **bun**.
## Build / Run / Test
All routine tasks go through `package.json` scripts and helper scripts in
`scripts/`:
```bash
bun install # install deps
bun run dev # vite dev server (frontend)
bun run tauri dev # run the desktop app
bun run check # svelte-check (types)
bun run test # vitest (frontend unit/integration)
bun run test:rust # cargo test (scripts/test-rust.sh)
bun run test:all # full suite (scripts/test-all.sh)
bun run test:e2e # webdriverio e2e
# Android — canonical entry points (see scripts/):
bun run android:build # debug APK
bun run android:build:release # release APK
bun run android:deploy # install to connected device
bun run android:dev # build + deploy
bun run android:logs # logcat
```
CI runs on **Gitea Actions** (`.gitea/workflows/`), not GitHub. Use the `gh` CLI
only against the mirror if one exists; the canonical remote is
`gitea.tourolle.paris`.
> **🔴 CI installs no system tools.** Never add an `apt-get`, `rustup`,
> `sdkmanager`, mingw/nsis, or any other *toolchain/system-package* install to a
> CI workflow step. Every build, test, and packaging **tool** must already live
> in the Docker image the job runs in — the unified builder (`Dockerfile.builder`
> → `gitea.tourolle.paris/dtourolle/jellytau-builder`) for Android/Linux/Windows,
> or `Dockerfile.arch` for Arch. If a job needs a tool the image lacks, **add it
> to the image, rebuild + push it** (`scripts/build-builder-image.sh`), and use
> it from CI — do not install it at job time. This keeps builds reproducible and
> fast, and is why the packaging stages are thin `FROM ${BUILDER_IMAGE}` layers.
>
> `bun install` (fetching the project's own JS deps per the lockfile) is **not**
> a violation — that's project dependencies, not a toolchain. The rule is about
> system tools, not npm/bun/cargo *packages* declared by the project.
## Before Committing
- Frontend: `bun run check` and `bun run test` must pass.
- Rust: `cd src-tauri && cargo fmt` then `cargo clippy`, plus `bun run test:rust`.
- **Boundary**: `bun run check:boundary` must pass — no domain taxonomy (Jellyfin
item-type category sets) leaked into the frontend. See below.
- **Traceability**: new requirement-implementing code must carry a `// TRACES:`
comment (see below).
- **Android source edits**: edit `src-tauri/android/src` (the canonical tree),
then run `scripts/sync-android-sources.sh` to sync into the `gen/` tree.
Never edit the generated `gen/` sources directly.
## Traceability (TRACES)
This project practices requirement-driven development: code that implements a
requirement is tagged with a `TRACES:` comment linking it to requirement IDs, and
an extraction tool builds the traceability matrix. **When you add or change code
that implements a requirement, add/update its TRACES comment.** Internal helpers
and requirement-less code stay untraced.
Format — `// TRACES: <URs> | <DRs> | <tests>`, e.g.:
```rust
/// TRACES: UR-005 | DR-001
pub enum PlayerState { }
```
```typescript
// TRACES: UR-005, UR-026 | DR-029
export function autoplayNextEpisode() { }
```
ID types: **UR** user requirement, **IR** integration, **DR** development, **JA**
Jellyfin API, **UT** unit test, **IT** integration test. Requirements are defined
in [docs/requirements.md](docs/requirements.md); the generated matrix is
[docs/traceability.md](docs/traceability.md).
Tooling:
```bash
bun run traces # extract traces (default format)
bun run traces:json # JSON — e.g. | jq '.byType' or '.requirements."UR-005"'
bun run traces:markdown # regenerate docs/traceability.md
git diff --name-only | xargs grep -L "TRACES:" # find untraced changed files
```
**CI is Gitea Actions** (`.gitea/workflows/`, remote `gitea.tourolle.paris`), not
GitHub. `traceability-check.yml` fails the build if coverage drops below
**50%** (`MIN_THRESHOLD`); `build-and-test.yml` runs frontend + Rust tests and an
Android `cargo check`. See [docs/traceability-ci.md](docs/traceability-ci.md) and
[docs/traces-quick-ref.md](docs/traces-quick-ref.md).
### Traces drive release notes
Prefer traceability over raw commit subjects when writing release notes for
[docs/release-checklist.md](docs/release-checklist.md). Raw `git log` subjects are
noisy; the TRACES graph gives a semantic summary of *what capabilities* the
release touched.
```bash
bun run release:notes # <latest tag>..HEAD
bun run release:notes v0.0.15..HEAD # explicit range
```
[scripts/release-notes.ts](scripts/release-notes.ts) resolves a commit range's
changed files → their `TRACES:` IDs → descriptions in
[docs/requirements.md](docs/requirements.md), then groups **UR** into *Features*
and **DR/IR** into *Improvements* (deduped, so many commits touching one
requirement collapse to one line). It also lists changed files that carry no
TRACES so nothing is silently dropped — those still need a manual line. Treat the
output as a reviewed draft, not a final changelog.
## Architecture
- **Rust backend** (`src-tauri/src/`) — all business logic: auth, catalog,
sessions, downloads, offline cache, playback control. Commands grouped by
domain in `src-tauri/src/commands/` (`auth.rs`, `catalog.rs`, `player/`,
`download/`, `offline.rs`, `sessions.rs`, …).
- **Svelte frontend** (`src/`) — presentation only. Stores in
`src/lib/stores/`, API wrappers in `src/lib/api/`, components in
`src/lib/components/`.
- **Playback layers** — Linux uses libmpv for direct playback and a WebKitGTK
HTML5 `<video>` element for HLS-transcoded (h264) streams; Android uses
ExoPlayer with a foreground media service + `MediaSessionCompat`.
- **tauri-specta** generates TypeScript bindings and typed events from the Rust
command/event definitions (registered via the Builder in `src-tauri/src/lib.rs`).
**Read the architecture docs before making structural changes** — they are the
canonical, maintained source; this file only summarizes. See
[docs/architecture/README.md](docs/architecture/README.md) and:
| Doc | Contents |
|-----|----------|
| [01-rust-backend.md](docs/architecture/01-rust-backend.md) | Player/session state machines, playback mode, queue, commands |
| [02-svelte-frontend.md](docs/architecture/02-svelte-frontend.md) | Stores, repository architecture, MiniPlayer, autoplay, nav guard |
| [03-data-flow.md](docs/architecture/03-data-flow.md) | Cache-first query flow, playback initiation, mode transfer |
| [04-type-sync-and-threading.md](docs/architecture/04-type-sync-and-threading.md) | **Rust↔TS type sync, the IPC camelCase convention + param table, locking** |
| [05-platform-backends.md](docs/architecture/05-platform-backends.md) | MpvBackend (Linux), ExoPlayerBackend (Android), MediaSession, HTML5 adapter |
| [06-downloads-and-offline.md](docs/architecture/06-downloads-and-offline.md) | Download manager/worker, smart cache, offline commands |
| [07-connectivity.md](docs/architecture/07-connectivity.md) | HTTP retry, ConnectivityMonitor, reachability model |
| [08-database-design.md](docs/architecture/08-database-design.md) | Tables, relationships, key queries |
| [09-security.md](docs/architecture/09-security.md) | Token storage, secure storage, network security |
Release process lives in [docs/release-checklist.md](docs/release-checklist.md)
and [docs/build-release.md](docs/build-release.md).
### Core principles (from the architecture docs)
- **Playback state is one-directional.** The player (ExoPlayer on Android, MPV on
Linux, session poller in remote mode) is the **authoritative source** of state
— position, pause, seeking, rate, track changes. The Svelte UI, OS
`MediaSession`/lockscreen, and MPRIS are **consumers**; they reflect what the
player reports and never determine it.
- **Unified player boundary.** UI controls playback *only* through the frontend
facade `src/lib/player/index.ts` (`playerController`) — never by calling
`commands.player*` directly. Webview HTML5 `<video>` reports its state back
into Rust via `src/lib/player/html5Adapter.ts` and the `player_report_*`
commands, so the controller stays the single source of truth in both native
and HTML5 modes.
- **Reachability from real traffic.** Server online/offline is derived from the
outcome of actual repository requests (reported to `ConnectivityMonitor`), not
a side-channel poller. The `/System/Info/Public` probe runs *only while
offline*, as a recovery detector.
- **Poison-tolerant locking.** Access shared `std::sync` state via the
`MutexSafe`/`RwLockSafe` helpers in `utils/lock.rs`, which recover a poisoned
lock instead of cascading a panic across the player.
- **Graceful backend init.** If a native player backend fails to initialize, the
app falls back to a no-op backend and emits `backend-init-failed` rather than
crashing.
- **Domain vocabulary lives in Rust.** The frontend is presentation-only and must
not encode Jellyfin's *taxonomy* — e.g. the set of item types that defines a
category like "Music". Send an opaque scope/enum across the boundary and let the
backend expand it. Single-type presentation (`itemType: "Movie"`, "this page
shows albums") is fine; a *category → set of types* mapping in `src/` is a leak.
`bun run check:boundary` is the tripwire; the real gate is the spec's layer
assignment. See [scoped-search-boundary.md](docs/specs/scoped-search-boundary.md)
for the incident this rule came from.
## Writing specs
New feature specs go in [docs/specs/](docs/specs/). **Start from
[SPEC-TEMPLATE.md](docs/specs/SPEC-TEMPLATE.md)** — its "Layer assignment" section
forces each piece of *logic* to be placed in the correct layer (Rust = domain,
frontend = presentation) *with a reason*, which is what prevents boundary leaks.
Before accepting a spec, run it past
[SPEC-REVIEW-CHECKLIST.md](docs/specs/SPEC-REVIEW-CHECKLIST.md). Do **not** frame
a spec around "no Rust changes required" — correct layer placement is the goal,
not minimal backend churn.
## Conventions
### Rust Backend
- Use `#[tauri::command]` for all IPC handlers.
- Prefer `async` commands for I/O-bound work.
- Return `Result<T, String>` from commands (the established convention here).
- Use `tauri::State<>` for shared state.
- Group related commands in domain modules under `commands/`.
- Use official Tauri plugins before writing custom native code.
### Frontend
- Use `invoke<T>()` from `@tauri-apps/api/core`, or the tauri-specta bindings.
- Define TS types matching the Rust structs; prefer the generated bindings.
- Handle IPC errors with try/catch.
- Use `@tauri-apps/api/path` for paths (never hardcode).
- Use `@tauri-apps/api/event` for backend→frontend events.
### 🔴 IPC parameter naming (Tauri v2)
The command **name** must match the Rust function name exactly
(`invoke("player_play_queue", …)`). But **parameter names do NOT** — Tauri v2's
`#[tauri::command]` macro auto-converts snake_case Rust params to **camelCase**
on the frontend:
```rust
#[tauri::command]
pub async fn cmd(repository_handle: String) { }
```
```typescript
await invoke("cmd", { repositoryHandle: "…" }); // camelCase, auto-converted
```
Nested struct fields need `#[serde(rename_all = "camelCase")]`; tagged unions use
`#[serde(tag = "type")]` and both sides must match the tag. Note: tauri-specta
tagged responses keep the Rust field names as-is (e.g. `new_url`, not `newUrl`).
### Events
- Backend events use **kebab-case** names (`download-event`, `search-event`).
- Emit from Rust via `emit(...)`; consume on the frontend via
`@tauri-apps/api/event` or the tauri-specta typed event bindings.
### Security
- Declare minimum permissions in `src-tauri/capabilities/`.
- Keep the CSP restrictive in `tauri.conf.json`.
- Validate all inputs in Rust command handlers.
- **Never read credentials** (tokens/keys from keyring, env, or stores) without
asking the user first.
## Gotchas (hard-won)
- **Never call sync/blocking APIs from event callbacks** that can re-enter the
player or hold a lock — it deadlocks. On Android, bind a locked
`AutoplayDecision` to a `let` *before* matching; a tokio `MutexGuard` held in
the `match` scrutinee deadlocks the `AdvanceToNext` arm.
- **VideoPlayer native mode**: no lifecycle calls after an `await` in `onMount`
(it flips to HTML5 mode and breaks Android seek).
- **Transcoded resume/seek**: `get_video_stream_url` must return the HLS
`master.m3u8`, not `stream.mp4`, or transcoded playback never starts.
- **Downloads** cap at 3 concurrent; the backend pump auto-starts pending rows.
Don't loop `startDownload` from the frontend.
- **Parallel Claude sessions**: the user may run concurrent sessions. Unexpected
file changes may be another session — check `git diff` before "repairing".
## Testing
### 🔴 Bug fixes: failing test FIRST, then the fix
When fixing a bug, **write a test that reproduces it and watch it fail before
touching the fix.** Red → green, in that order:
1. Write a test that exercises the broken behavior and **run it — it must fail**,
proving the test actually catches the bug (a test that passes before the fix
proves nothing).
2. Apply the fix.
3. Re-run — the test now passes, and so does the rest of the suite.
Never fix first and backfill the test afterward: a test written against
already-fixed code can pass for the wrong reason and silently fails to guard the
regression. If the logic is buried in a component, extract the pure part into a
plain `.ts` module (e.g. `episodeStrip.ts`) so it can be unit-tested — the same
pattern as `TrackList.logic.test.ts`.
```bash
# Rust
cd src-tauri && cargo test
cd src-tauri && cargo test test_name # single test
# Frontend
bun run test
bun run test:coverage
# Tauri IPC param-naming integration tests (guard the camelCase rule):
bun run test -- tauriIntegration.test.ts
```
-152
View File
@@ -1,152 +0,0 @@
# Multi-stage build for JellyTau - Tauri Jellyfin client
#
# The desktop packaging stages (desktop-linux-build, windows-cross) build FROM
# the unified registry builder image, which carries every packaging tool. Declared
# here (before the first FROM) so it's in scope for those stages' FROM lines.
# Override for local iteration: --build-arg BUILDER_IMAGE=jellytau-builder:latest
ARG BUILDER_IMAGE=gitea.tourolle.paris/dtourolle/jellytau-builder:latest
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 \
PATH="/root/.bun/bin:/root/.cargo/bin:$PATH" \
CARGO_HOME=/root/.cargo
# Install system dependencies
RUN apt-get update && apt-get install -y --no-install-recommends \
# Build essentials
build-essential \
curl \
wget \
git \
ca-certificates \
unzip \
# 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 \
# Tauri Linux desktop dependencies (needed for `cargo test` on the host target)
libglib2.0-dev \
libgtk-3-dev \
libwebkit2gtk-4.1-dev \
libjavascriptcoregtk-4.1-dev \
libsoup-3.0-dev \
librsvg2-dev \
libayatana-appindicator3-dev \
# mpv player library (linked via libmpv-sys)
libmpv-dev \
&& rm -rf /var/lib/apt/lists/*
# Install Node.js 20.x from NodeSource
RUN curl -fsSL https://deb.nodesource.com/setup_20.x | bash - && \
apt-get install -y --no-install-recommends nodejs && \
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
# Install Rust using rustup
RUN curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y && \
. $HOME/.cargo/env && \
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..." && \
bunx svelte-kit sync && \
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!"
# Desktop packaging stages build FROM the unified registry builder image (see the
# BUILDER_IMAGE ARG at the top), which already carries every packaging tool
# (rpm/file for Linux, mingw-w64 + nsis + the x86_64-pc-windows-gnu rust target
# for Windows). ONE source of dependency truth, shared with CI — no per-stage
# apt/rustup here.
# Linux desktop packaging environment (deb + rpm; Arch is Dockerfile.arch).
# Thin layer over the builder — the actual build runs at container-run time on
# the bind-mounted source (see docker-compose.yml / scripts/build-desktop-linux.sh),
# matching the `dev` service model. Run standalone with:
# docker run --rm -v "$PWD:/app" -v "$PWD/dist:/app/dist" <img> \
# bash -c "OUTPUT_DIR=/app/dist scripts/build-desktop-linux.sh"
FROM ${BUILDER_IMAGE} AS desktop-linux-build
WORKDIR /app
CMD ["bash", "-c", "OUTPUT_DIR=/app/dist scripts/build-desktop-linux.sh"]
# Windows cross-compile environment (MSVC target via cargo-xwin). Video works via
# WebView2 and audio via the webview <audio> backend; NSIS installer is produced
# from Linux by cargo-xwin. Default bundles NSIS; override WIN_BUNDLES=none for
# exe-only. Build runs at container-run time like above.
FROM ${BUILDER_IMAGE} AS windows-cross
WORKDIR /app
CMD ["bash", "-c", "OUTPUT_DIR=/app/dist WIN_BUNDLES=${WIN_BUNDLES:-nsis} scripts/build-windows-cross.sh"]
# 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/"]
-37
View File
@@ -1,37 +0,0 @@
# JellyTau Arch Linux package builder.
#
# Tauri has no pacman bundle target, so we build a real .pkg.tar.zst with makepkg
# from packaging/arch/PKGBUILD. makepkg refuses to run as root, so we create a
# non-root `builder` user with passwordless sudo (for `makepkg -s` pacman calls).
#
# docker build -f Dockerfile.arch -t jellytau-arch .
# docker run --rm -v "$PWD/dist:/out" jellytau-arch
FROM archlinux:latest
RUN pacman -Syu --noconfirm \
base-devel git sudo \
rust cargo nodejs \
webkit2gtk-4.1 mpv gtk3 libayatana-appindicator \
libsoup3 pkgconf openssl \
&& pacman -Scc --noconfirm
# Bun is not in the official repos; install the upstream binary.
RUN curl -fsSL https://bun.sh/install | bash && \
ln -s /root/.bun/bin/bun /usr/local/bin/bun
# Non-root build user with passwordless sudo for makepkg's dependency step.
RUN useradd -m builder && \
echo 'builder ALL=(ALL) NOPASSWD: ALL' > /etc/sudoers.d/builder && \
ln -sf /root/.bun/bin/bun /usr/local/bin/bun
WORKDIR /app
COPY . .
RUN chown -R builder:builder /app
USER builder
ENV OUTPUT_DIR=/out
RUN mkdir -p /out
VOLUME ["/out"]
# Default: build the package. Output lands in /out (mount it to collect the pkg).
CMD ["bash", "-c", "OUTPUT_DIR=/out scripts/build-arch.sh"]
-120
View File
@@ -1,120 +0,0 @@
# JellyTau Builder Image
# Pre-built image with all dependencies for building, testing, and packaging:
# - Android APK (SDK/NDK), Linux desktop (deb/rpm),
# - Windows cross via the official Tauri path: MSVC target + cargo-xwin + NSIS
# Arch packages build in a separate archlinux image (Dockerfile.arch) since
# makepkg is Arch-specific.
# 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=36 \
BUILD_TOOLS_VERSION=35.0.0 \
RUST_BACKTRACE=1 \
PATH="/root/.bun/bin:/root/.cargo/bin:$PATH" \
CARGO_HOME=/root/.cargo
# Install system dependencies
RUN apt-get update && apt-get install -y --no-install-recommends \
build-essential \
curl \
wget \
git \
ca-certificates \
unzip \
jq \
openjdk-17-jdk-headless \
pkg-config \
libssl-dev \
libclang-dev \
llvm-dev \
# Tauri Linux desktop dependencies (needed for `cargo test` on the host target)
libglib2.0-dev \
libgtk-3-dev \
libwebkit2gtk-4.1-dev \
libjavascriptcoregtk-4.1-dev \
libsoup-3.0-dev \
librsvg2-dev \
libayatana-appindicator3-dev \
# mpv player library (linked via libmpv-sys)
libmpv-dev \
&& rm -rf /var/lib/apt/lists/*
# Install Node.js 20.x from NodeSource
RUN curl -fsSL https://deb.nodesource.com/setup_20.x | bash - && \
apt-get install -y --no-install-recommends nodejs && \
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
# Install Rust using rustup
RUN curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y && \
. $HOME/.cargo/env && \
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
# Accept all SDK licenses up front so Gradle can install/use components non-interactively
RUN yes | $ANDROID_HOME/cmdline-tools/latest/bin/sdkmanager --sdk_root=$ANDROID_HOME --licenses > /dev/null
# Install Android SDK components (must match the compileSdk/targetSdk in the generated Gradle project)
RUN $ANDROID_HOME/cmdline-tools/latest/bin/sdkmanager --sdk_root=$ANDROID_HOME \
"platform-tools" \
"platforms;android-$SDK_VERSION" \
"build-tools;$BUILD_TOOLS_VERSION" \
"ndk;$NDK_VERSION" \
--channel=0 2>&1 | grep -v "Warning" || true
# Set NDK environment variable
ENV NDK_HOME=$ANDROID_HOME/ndk/$NDK_VERSION
# ---------------------------------------------------------------------------
# Desktop packaging tools — kept in a trailing layer ON PURPOSE so that adding
# or changing a packaging tool doesn't invalidate the expensive apt/rust/Android
# layers above (a tool tweak becomes a ~1-2 min rebuild, not ~15). Covers Linux
# (deb/rpm) and Windows cross (MSVC via cargo-xwin + NSIS).
RUN apt-get update && apt-get install -y --no-install-recommends \
# Linux desktop packaging: rpmbuild for the .rpm bundle (deb needs nothing extra)
rpm \
file \
# Windows cross-compile (official Tauri path: MSVC target via cargo-xwin).
# clang provides clang-cl, the MSVC-compatible C compiler cc-rs uses to build
# C deps (bundled sqlite, ring, ...); lld = linker; llvm = llvm-lib/ar etc;
# nsis = installer generator.
clang \
lld \
llvm \
nsis \
&& rm -rf /var/lib/apt/lists/* \
# Ubuntu's clang package ships clang but NOT the clang-cl alias that cc-rs
# invokes for MSVC targets. clang-cl is the same binary in MSVC-compat mode,
# so provide it as a symlink.
&& ln -sf /usr/bin/clang /usr/local/bin/clang-cl
# Windows rust target + cargo-xwin (downloads the MSVC CRT/SDK at build time).
RUN . $HOME/.cargo/env && \
rustup target add x86_64-pc-windows-msvc && \
cargo install --locked cargo-xwin
WORKDIR /app
ENTRYPOINT ["/bin/bash"]
File diff suppressed because one or more lines are too long
Binary file not shown.
Binary file not shown.
File diff suppressed because it is too large Load Diff

After

Width:  |  Height:  |  Size: 434 KiB

Binary file not shown.
Binary file not shown.
Binary file not shown.
-60
View File
@@ -1,60 +0,0 @@
<h1 align="center">
<img src="docs/assets/logo.png" alt="JellyTau logo" width="120" /><br />
JellyTau
</h1>
A cross-platform Jellyfin client built with Tauri, SvelteKit, and TypeScript.
Business logic lives in a Rust backend; a UI-rich Svelte frontend handles
presentation and talks to it over Tauri's IPC. Targets Linux (libmpv) and
Android (ExoPlayer).
## Getting Started
This project uses [bun](https://bun.sh) as its package manager.
```bash
# Activate the Rust environment (fish shell)
source "$HOME/.cargo/env.fish"
# Install dependencies
bun install
# Run in development
bun run tauri dev
# Type-check the frontend
bun run check
# Build for Linux
bun run tauri build
# Build for Android
bun run tauri android build
```
For the full set of build, test, and Android helper scripts, see
[scripts/README.md](scripts/README.md).
## Documentation
| Topic | Location |
|-------|----------|
| Architecture overview & subsystem docs | [docs/architecture/](docs/architecture/) |
| Requirements, traceability & technical debt | [docs/requirements.md](docs/requirements.md) |
| Build & release process | [docs/build-release.md](docs/build-release.md) |
| Docker builds | [docs/build/docker.md](docs/build/docker.md) |
| Traceability tooling & CI | [docs/traceability.md](docs/traceability.md), [docs/traceability-ci.md](docs/traceability-ci.md) |
| Release checklist | [docs/release-checklist.md](docs/release-checklist.md) |
| UX flows | [docs/ux-flows.md](docs/ux-flows.md) |
## Recommended IDE Setup
[VS Code](https://code.visualstudio.com/) +
[Svelte](https://marketplace.visualstudio.com/items?itemName=svelte.svelte-vscode) +
[Tauri](https://marketplace.visualstudio.com/items?itemName=tauri-apps.tauri-vscode) +
[rust-analyzer](https://marketplace.visualstudio.com/items?itemName=rust-lang.rust-analyzer).
## License
MIT
+230
View File
File diff suppressed because one or more lines are too long
View File
+2
View File
@@ -0,0 +1,2 @@
window.ALL_CRATES = ["jellytau","jellytau_lib"];
//{"start":21,"fragment_lengths":[10,15]}
+1
View File
@@ -0,0 +1 @@
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="Documentation for Rustdoc"><title>Help</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-6b053e98.ttf.woff2,FiraSans-Italic-81dc35de.woff2,FiraSans-Regular-0fe48ade.woff2,FiraSans-MediumItalic-ccf7e434.woff2,FiraSans-Medium-e1aa3f0a.woff2,SourceCodePro-Regular-8badfe75.ttf.woff2,SourceCodePro-Semibold-aa29a496.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2"href="./static.files/${f}">`).join(""))</script><link rel="stylesheet" href="./static.files/normalize-9960930a.css"><link rel="stylesheet" href="./static.files/rustdoc-17e0aaed.css"><meta name="rustdoc-vars" data-root-path="./" data-static-root-path="./static.files/" data-current-crate="jellytau" data-themes="" data-resource-suffix="" data-rustdoc-version="1.97.1 (8bab26f4f 2026-07-14)" data-channel="1.97.1" data-search-js="search-fd9372ac.js" data-stringdex-js="stringdex-2da4960a.js" data-settings-js="settings-170eb4bf.js" ><script src="./static.files/storage-41dd4d93.js"></script><script defer src="./static.files/main-fcd733ba.js"></script><noscript><link rel="stylesheet" href="./static.files/noscript-f7c3ffd8.css"></noscript><link rel="alternate icon" type="image/png" href="./static.files/favicon-32x32-eab170b8.png"><link rel="icon" type="image/svg+xml" href="./static.files/favicon-044be391.svg"></head><body class="rustdoc mod sys"><a class="skip-main-content" href="#main-content">Skip to main content</a><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><rustdoc-topbar><h2><a href="#">All</a></h2></rustdoc-topbar><nav class="sidebar"><div class="sidebar-crate"><a class="logo-container" href="./index.html"><img class="rust-logo" src="./static.files/rust-logo-9a9549ea.svg" alt="logo"></a><h2><a href="./index.html">Rustdoc</a><span class="version">1.97.1</span></h2></div><div class="version">(8bab26f4f 2026-07-14)</div><h2 class="location">Help</h2><div class="sidebar-elems"></div></nav><div class="sidebar-resizer" title="Drag to resize sidebar"></div><main><div class="width-limiter"><section id="main-content" class="content" tabindex="-1"><div class="main-heading"><h1>Rustdoc help</h1><span class="out-of-band"><a id="back" href="javascript:void(0)" onclick="history.back();">Back</a></span></div><noscript><section><p>You need to enable JavaScript to use keyboard commands or search.</p><p>For more information, browse the <a href="https://doc.rust-lang.org/1.97.1/rustdoc/">rustdoc handbook</a>.</p></section></noscript></section></div></main></body></html>
+1
View File
@@ -0,0 +1 @@
<meta http-equiv="refresh" content="0; url=jellytau_lib/index.html">
+1
View File
@@ -0,0 +1 @@
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="List of all items in this crate"><title>List of all items in this crate</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-6b053e98.ttf.woff2,FiraSans-Italic-81dc35de.woff2,FiraSans-Regular-0fe48ade.woff2,FiraSans-MediumItalic-ccf7e434.woff2,FiraSans-Medium-e1aa3f0a.woff2,SourceCodePro-Regular-8badfe75.ttf.woff2,SourceCodePro-Semibold-aa29a496.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2"href="../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../static.files/normalize-9960930a.css"><link rel="stylesheet" href="../static.files/rustdoc-17e0aaed.css"><meta name="rustdoc-vars" data-root-path="../" data-static-root-path="../static.files/" data-current-crate="jellytau" data-themes="" data-resource-suffix="" data-rustdoc-version="1.97.1 (8bab26f4f 2026-07-14)" data-channel="1.97.1" data-search-js="search-fd9372ac.js" data-stringdex-js="stringdex-2da4960a.js" data-settings-js="settings-170eb4bf.js" ><script src="../static.files/storage-41dd4d93.js"></script><script defer src="../static.files/main-fcd733ba.js"></script><noscript><link rel="stylesheet" href="../static.files/noscript-f7c3ffd8.css"></noscript><link rel="alternate icon" type="image/png" href="../static.files/favicon-32x32-eab170b8.png"><link rel="icon" type="image/svg+xml" href="../static.files/favicon-044be391.svg"></head><body class="rustdoc mod sys"><a class="skip-main-content" href="#main-content">Skip to main content</a><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><rustdoc-topbar><h2><a href="#">All</a></h2></rustdoc-topbar><nav class="sidebar"><div class="sidebar-crate"><h2><a href="../jellytau/index.html">jellytau</a><span class="version">0.11.1</span></h2></div><div class="sidebar-elems"><section id="rustdoc-toc"><h3><a href="#functions">Crate Items</a></h3><ul class="block"><li><a href="#functions" title="Functions">Functions</a></li></ul></section><div id="rustdoc-modnav"></div></div></nav><div class="sidebar-resizer" title="Drag to resize sidebar"></div><main><div class="width-limiter"><section id="main-content" class="content" tabindex="-1"><div class="main-heading"><h1>List of all items</h1><rustdoc-toolbar></rustdoc-toolbar></div><h3 id="functions">Functions</h3><ul class="all-items"><li><a href="fn.main.html">main</a></li></ul></section></div></main></body></html>
+1
View File
@@ -0,0 +1 @@
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="API documentation for the Rust `main` fn in crate `jellytau`."><title>main in jellytau - Rust</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-6b053e98.ttf.woff2,FiraSans-Italic-81dc35de.woff2,FiraSans-Regular-0fe48ade.woff2,FiraSans-MediumItalic-ccf7e434.woff2,FiraSans-Medium-e1aa3f0a.woff2,SourceCodePro-Regular-8badfe75.ttf.woff2,SourceCodePro-Semibold-aa29a496.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2"href="../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../static.files/normalize-9960930a.css"><link rel="stylesheet" href="../static.files/rustdoc-17e0aaed.css"><meta name="rustdoc-vars" data-root-path="../" data-static-root-path="../static.files/" data-current-crate="jellytau" data-themes="" data-resource-suffix="" data-rustdoc-version="1.97.1 (8bab26f4f 2026-07-14)" data-channel="1.97.1" data-search-js="search-fd9372ac.js" data-stringdex-js="stringdex-2da4960a.js" data-settings-js="settings-170eb4bf.js" ><script src="../static.files/storage-41dd4d93.js"></script><script defer src="sidebar-items.js"></script><script defer src="../static.files/main-fcd733ba.js"></script><noscript><link rel="stylesheet" href="../static.files/noscript-f7c3ffd8.css"></noscript><link rel="alternate icon" type="image/png" href="../static.files/favicon-32x32-eab170b8.png"><link rel="icon" type="image/svg+xml" href="../static.files/favicon-044be391.svg"></head><body class="rustdoc fn"><a class="skip-main-content" href="#main-content">Skip to main content</a><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><rustdoc-topbar><h2><a href="#">main</a></h2></rustdoc-topbar><nav class="sidebar"><div class="sidebar-crate"><h2><a href="../jellytau/index.html">jellytau</a><span class="version">0.11.1</span></h2></div><div class="sidebar-elems"><div id="rustdoc-modnav"></div></div></nav><div class="sidebar-resizer" title="Drag to resize sidebar"></div><main><div class="width-limiter"><section id="main-content" class="content" tabindex="-1"><div class="main-heading"><div class="rustdoc-breadcrumbs"><a href="index.html">jellytau</a></div><h1>Function <span class="fn">main</span>&nbsp;<button id="copy-path" title="Copy item path to clipboard">Copy item path</button></h1><rustdoc-toolbar></rustdoc-toolbar><span class="sub-heading"><a class="src" href="../src/jellytau/main.rs.html#4-6">Source</a> </span></div><pre class="rust item-decl"><code>pub(crate) fn main()</code></pre></section></div></main></body></html>
+1
View File
@@ -0,0 +1 @@
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="API documentation for the Rust `jellytau` crate."><title>jellytau - Rust</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-6b053e98.ttf.woff2,FiraSans-Italic-81dc35de.woff2,FiraSans-Regular-0fe48ade.woff2,FiraSans-MediumItalic-ccf7e434.woff2,FiraSans-Medium-e1aa3f0a.woff2,SourceCodePro-Regular-8badfe75.ttf.woff2,SourceCodePro-Semibold-aa29a496.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2"href="../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../static.files/normalize-9960930a.css"><link rel="stylesheet" href="../static.files/rustdoc-17e0aaed.css"><meta name="rustdoc-vars" data-root-path="../" data-static-root-path="../static.files/" data-current-crate="jellytau" data-themes="" data-resource-suffix="" data-rustdoc-version="1.97.1 (8bab26f4f 2026-07-14)" data-channel="1.97.1" data-search-js="search-fd9372ac.js" data-stringdex-js="stringdex-2da4960a.js" data-settings-js="settings-170eb4bf.js" ><script src="../static.files/storage-41dd4d93.js"></script><script defer src="../crates.js"></script><script defer src="../static.files/main-fcd733ba.js"></script><noscript><link rel="stylesheet" href="../static.files/noscript-f7c3ffd8.css"></noscript><link rel="alternate icon" type="image/png" href="../static.files/favicon-32x32-eab170b8.png"><link rel="icon" type="image/svg+xml" href="../static.files/favicon-044be391.svg"></head><body class="rustdoc mod crate"><a class="skip-main-content" href="#main-content">Skip to main content</a><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><rustdoc-topbar><h2><a href="#">Crate jellytau</a></h2></rustdoc-topbar><nav class="sidebar"><div class="sidebar-crate"><h2><a href="../jellytau/index.html">jellytau</a><span class="version">0.11.1</span></h2></div><div class="sidebar-elems"><ul class="block"><li><a id="all-types" href="all.html">All Items</a></li></ul><section id="rustdoc-toc"><h3><a href="#functions">Crate Items</a></h3><ul class="block"><li><a href="#functions" title="Functions">Functions</a></li></ul></section><div id="rustdoc-modnav"></div></div></nav><div class="sidebar-resizer" title="Drag to resize sidebar"></div><main><div class="width-limiter"><section id="main-content" class="content" tabindex="-1"><div class="main-heading"><h1>Crate <span>jellytau</span>&nbsp;<button id="copy-path" title="Copy item path to clipboard">Copy item path</button></h1><rustdoc-toolbar></rustdoc-toolbar><span class="sub-heading"><a class="src" href="../src/jellytau/main.rs.html#2-6">Source</a> </span></div><h2 id="functions" class="section-header">Functions<a href="#functions" class="anchor">§</a></h2><dl class="item-table"><dt><a class="fn" href="fn.main.html" title="fn jellytau::main">main</a><span title="Restricted Visibility">&nbsp;🔒</span> </dt></dl></section></div></main></body></html>
+1
View File
@@ -0,0 +1 @@
window.SIDEBAR_ITEMS = {"fn":["main"]};
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -0,0 +1 @@
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="API documentation for the Rust `VERIFICATION_INTERVAL_MS` constant in crate `jellytau_lib`."><title>VERIFICATION_INTERVAL_MS in jellytau_lib::auth::session_verifier - Rust</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-6b053e98.ttf.woff2,FiraSans-Italic-81dc35de.woff2,FiraSans-Regular-0fe48ade.woff2,FiraSans-MediumItalic-ccf7e434.woff2,FiraSans-Medium-e1aa3f0a.woff2,SourceCodePro-Regular-8badfe75.ttf.woff2,SourceCodePro-Semibold-aa29a496.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2"href="../../../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../../../static.files/normalize-9960930a.css"><link rel="stylesheet" href="../../../static.files/rustdoc-17e0aaed.css"><meta name="rustdoc-vars" data-root-path="../../../" data-static-root-path="../../../static.files/" data-current-crate="jellytau_lib" data-themes="" data-resource-suffix="" data-rustdoc-version="1.97.1 (8bab26f4f 2026-07-14)" data-channel="1.97.1" data-search-js="search-fd9372ac.js" data-stringdex-js="stringdex-2da4960a.js" data-settings-js="settings-170eb4bf.js" ><script src="../../../static.files/storage-41dd4d93.js"></script><script defer src="sidebar-items.js"></script><script defer src="../../../static.files/main-fcd733ba.js"></script><noscript><link rel="stylesheet" href="../../../static.files/noscript-f7c3ffd8.css"></noscript><link rel="alternate icon" type="image/png" href="../../../static.files/favicon-32x32-eab170b8.png"><link rel="icon" type="image/svg+xml" href="../../../static.files/favicon-044be391.svg"></head><body class="rustdoc constant"><a class="skip-main-content" href="#main-content">Skip to main content</a><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><rustdoc-topbar><h2><a href="#">VERIFICATION_INTERVAL_MS</a></h2></rustdoc-topbar><nav class="sidebar"><div class="sidebar-crate"><h2><a href="../../../jellytau_lib/index.html">jellytau_<wbr>lib</a><span class="version">0.11.1</span></h2></div><div class="sidebar-elems"><div id="rustdoc-modnav"><h2><a href="index.html">In jellytau_<wbr>lib::<wbr>auth::<wbr>session_<wbr>verifier</a></h2></div></div></nav><div class="sidebar-resizer" title="Drag to resize sidebar"></div><main><div class="width-limiter"><section id="main-content" class="content" tabindex="-1"><div class="main-heading"><div class="rustdoc-breadcrumbs"><a href="../../index.html">jellytau_lib</a>::<wbr><a href="../index.html">auth</a>::<wbr><a href="index.html">session_verifier</a></div><h1>Constant <span class="constant">VERIFICATION_<wbr>INTERVAL_<wbr>MS</span>&nbsp;<button id="copy-path" title="Copy item path to clipboard">Copy item path</button></h1><rustdoc-toolbar></rustdoc-toolbar><span class="sub-heading"><a class="src" href="../../../src/jellytau_lib/auth/session_verifier.rs.html#10">Source</a> </span></div><pre class="rust item-decl"><code>const VERIFICATION_INTERVAL_MS: <a class="primitive" href="https://doc.rust-lang.org/1.97.1/std/primitive.u64.html">u64</a> = 300000;</code></pre></section></div></main></body></html>
File diff suppressed because one or more lines are too long
@@ -0,0 +1 @@
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="API documentation for the Rust `session_verifier` mod in crate `jellytau_lib`."><title>jellytau_lib::auth::session_verifier - Rust</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-6b053e98.ttf.woff2,FiraSans-Italic-81dc35de.woff2,FiraSans-Regular-0fe48ade.woff2,FiraSans-MediumItalic-ccf7e434.woff2,FiraSans-Medium-e1aa3f0a.woff2,SourceCodePro-Regular-8badfe75.ttf.woff2,SourceCodePro-Semibold-aa29a496.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2"href="../../../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../../../static.files/normalize-9960930a.css"><link rel="stylesheet" href="../../../static.files/rustdoc-17e0aaed.css"><meta name="rustdoc-vars" data-root-path="../../../" data-static-root-path="../../../static.files/" data-current-crate="jellytau_lib" data-themes="" data-resource-suffix="" data-rustdoc-version="1.97.1 (8bab26f4f 2026-07-14)" data-channel="1.97.1" data-search-js="search-fd9372ac.js" data-stringdex-js="stringdex-2da4960a.js" data-settings-js="settings-170eb4bf.js" ><script src="../../../static.files/storage-41dd4d93.js"></script><script defer src="../sidebar-items.js"></script><script defer src="../../../static.files/main-fcd733ba.js"></script><noscript><link rel="stylesheet" href="../../../static.files/noscript-f7c3ffd8.css"></noscript><link rel="alternate icon" type="image/png" href="../../../static.files/favicon-32x32-eab170b8.png"><link rel="icon" type="image/svg+xml" href="../../../static.files/favicon-044be391.svg"></head><body class="rustdoc mod"><a class="skip-main-content" href="#main-content">Skip to main content</a><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><rustdoc-topbar><h2><a href="#">Module session_verifier</a></h2></rustdoc-topbar><nav class="sidebar"><div class="sidebar-crate"><h2><a href="../../../jellytau_lib/index.html">jellytau_<wbr>lib</a><span class="version">0.11.1</span></h2></div><div class="sidebar-elems"><section id="rustdoc-toc"><h2 class="location"><a href="#">Module session_<wbr>verifier</a></h2><h3><a href="#structs">Module Items</a></h3><ul class="block"><li><a href="#structs" title="Structs">Structs</a></li><li><a href="#enums" title="Enums">Enums</a></li><li><a href="#constants" title="Constants">Constants</a></li></ul></section><div id="rustdoc-modnav"><h2><a href="../index.html">In jellytau_<wbr>lib::<wbr>auth</a></h2></div></div></nav><div class="sidebar-resizer" title="Drag to resize sidebar"></div><main><div class="width-limiter"><section id="main-content" class="content" tabindex="-1"><div class="main-heading"><div class="rustdoc-breadcrumbs"><a href="../../index.html">jellytau_lib</a>::<wbr><a href="../index.html">auth</a></div><h1>Module <span>session_<wbr>verifier</span>&nbsp;<button id="copy-path" title="Copy item path to clipboard">Copy item path</button></h1><rustdoc-toolbar></rustdoc-toolbar><span class="sub-heading"><a class="src" href="../../../src/jellytau_lib/auth/session_verifier.rs.html#1-170">Source</a> </span></div><h2 id="structs" class="section-header">Structs<a href="#structs" class="anchor">§</a></h2><dl class="item-table"><dt><a class="struct" href="struct.SessionVerifier.html" title="struct jellytau_lib::auth::session_verifier::SessionVerifier">Session<wbr>Verifier</a></dt><dd>Background session verifier</dd></dl><h2 id="enums" class="section-header">Enums<a href="#enums" class="anchor">§</a></h2><dl class="item-table"><dt><a class="enum" href="enum.SessionVerificationEvent.html" title="enum jellytau_lib::auth::session_verifier::SessionVerificationEvent">Session<wbr>Verification<wbr>Event</a></dt><dd>Session verification result event emitted to frontend</dd></dl><h2 id="constants" class="section-header">Constants<a href="#constants" class="anchor">§</a></h2><dl class="item-table"><dt><a class="constant" href="constant.VERIFICATION_INTERVAL_MS.html" title="constant jellytau_lib::auth::session_verifier::VERIFICATION_INTERVAL_MS">VERIFICATION_<wbr>INTERVAL_<wbr>MS</a><span title="Restricted Visibility">&nbsp;🔒</span> </dt></dl></section></div></main></body></html>
@@ -0,0 +1 @@
window.SIDEBAR_ITEMS = {"constant":["VERIFICATION_INTERVAL_MS"],"enum":["SessionVerificationEvent"],"struct":["SessionVerifier"]};
File diff suppressed because one or more lines are too long
+1
View File
@@ -0,0 +1 @@
window.SIDEBAR_ITEMS = {"mod":["session_verifier"],"struct":["AuthManager","AuthResult","AuthenticateByNameResponse","JellyfinUser","PublicSystemInfo","ServerInfo","Session","User"]};
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -0,0 +1,5 @@
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="Connect to a Jellyfin server and get server info"><title>auth_connect_to_server in jellytau_lib::commands::auth - Rust</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-6b053e98.ttf.woff2,FiraSans-Italic-81dc35de.woff2,FiraSans-Regular-0fe48ade.woff2,FiraSans-MediumItalic-ccf7e434.woff2,FiraSans-Medium-e1aa3f0a.woff2,SourceCodePro-Regular-8badfe75.ttf.woff2,SourceCodePro-Semibold-aa29a496.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2"href="../../../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../../../static.files/normalize-9960930a.css"><link rel="stylesheet" href="../../../static.files/rustdoc-17e0aaed.css"><meta name="rustdoc-vars" data-root-path="../../../" data-static-root-path="../../../static.files/" data-current-crate="jellytau_lib" data-themes="" data-resource-suffix="" data-rustdoc-version="1.97.1 (8bab26f4f 2026-07-14)" data-channel="1.97.1" data-search-js="search-fd9372ac.js" data-stringdex-js="stringdex-2da4960a.js" data-settings-js="settings-170eb4bf.js" ><script src="../../../static.files/storage-41dd4d93.js"></script><script defer src="sidebar-items.js"></script><script defer src="../../../static.files/main-fcd733ba.js"></script><noscript><link rel="stylesheet" href="../../../static.files/noscript-f7c3ffd8.css"></noscript><link rel="alternate icon" type="image/png" href="../../../static.files/favicon-32x32-eab170b8.png"><link rel="icon" type="image/svg+xml" href="../../../static.files/favicon-044be391.svg"></head><body class="rustdoc fn"><a class="skip-main-content" href="#main-content">Skip to main content</a><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><rustdoc-topbar><h2><a href="#">auth_connect_to_server</a></h2></rustdoc-topbar><nav class="sidebar"><div class="sidebar-crate"><h2><a href="../../../jellytau_lib/index.html">jellytau_<wbr>lib</a><span class="version">0.11.1</span></h2></div><div class="sidebar-elems"><div id="rustdoc-modnav"><h2><a href="index.html">In jellytau_<wbr>lib::<wbr>commands::<wbr>auth</a></h2></div></div></nav><div class="sidebar-resizer" title="Drag to resize sidebar"></div><main><div class="width-limiter"><section id="main-content" class="content" tabindex="-1"><div class="main-heading"><div class="rustdoc-breadcrumbs"><a href="../../index.html">jellytau_lib</a>::<wbr><a href="../index.html">commands</a>::<wbr><a href="index.html">auth</a></div><h1>Function <span class="fn">auth_<wbr>connect_<wbr>to_<wbr>server</span>&nbsp;<button id="copy-path" title="Copy item path to clipboard">Copy item path</button></h1><rustdoc-toolbar></rustdoc-toolbar><span class="sub-heading"><a class="src" href="../../../src/jellytau_lib/commands/auth.rs.html#75-80">Source</a> </span></div><pre class="rust item-decl"><code>pub async fn auth_connect_to_server(
server_url: <a class="struct" href="https://doc.rust-lang.org/1.97.1/alloc/string/struct.String.html" title="struct alloc::string::String">String</a>,
auth_manager: State&lt;'_, <a class="struct" href="struct.AuthManagerWrapper.html" title="struct jellytau_lib::commands::auth::AuthManagerWrapper">AuthManagerWrapper</a>&gt;,
) -&gt; <a class="enum" href="https://doc.rust-lang.org/1.97.1/core/result/enum.Result.html" title="enum core::result::Result">Result</a>&lt;<a class="struct" href="../../auth/struct.ServerInfo.html" title="struct jellytau_lib::auth::ServerInfo">ServerInfo</a>, <a class="struct" href="https://doc.rust-lang.org/1.97.1/alloc/string/struct.String.html" title="struct alloc::string::String">String</a>&gt;</code></pre><details class="toggle top-doc" open><summary class="hideme"><span>Expand description</span></summary><div class="docblock"><p>Connect to a Jellyfin server and get server info</p>
</div></details></section></div></main></body></html>
@@ -0,0 +1,4 @@
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="Get current session"><title>auth_get_session in jellytau_lib::commands::auth - Rust</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-6b053e98.ttf.woff2,FiraSans-Italic-81dc35de.woff2,FiraSans-Regular-0fe48ade.woff2,FiraSans-MediumItalic-ccf7e434.woff2,FiraSans-Medium-e1aa3f0a.woff2,SourceCodePro-Regular-8badfe75.ttf.woff2,SourceCodePro-Semibold-aa29a496.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2"href="../../../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../../../static.files/normalize-9960930a.css"><link rel="stylesheet" href="../../../static.files/rustdoc-17e0aaed.css"><meta name="rustdoc-vars" data-root-path="../../../" data-static-root-path="../../../static.files/" data-current-crate="jellytau_lib" data-themes="" data-resource-suffix="" data-rustdoc-version="1.97.1 (8bab26f4f 2026-07-14)" data-channel="1.97.1" data-search-js="search-fd9372ac.js" data-stringdex-js="stringdex-2da4960a.js" data-settings-js="settings-170eb4bf.js" ><script src="../../../static.files/storage-41dd4d93.js"></script><script defer src="sidebar-items.js"></script><script defer src="../../../static.files/main-fcd733ba.js"></script><noscript><link rel="stylesheet" href="../../../static.files/noscript-f7c3ffd8.css"></noscript><link rel="alternate icon" type="image/png" href="../../../static.files/favicon-32x32-eab170b8.png"><link rel="icon" type="image/svg+xml" href="../../../static.files/favicon-044be391.svg"></head><body class="rustdoc fn"><a class="skip-main-content" href="#main-content">Skip to main content</a><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><rustdoc-topbar><h2><a href="#">auth_get_session</a></h2></rustdoc-topbar><nav class="sidebar"><div class="sidebar-crate"><h2><a href="../../../jellytau_lib/index.html">jellytau_<wbr>lib</a><span class="version">0.11.1</span></h2></div><div class="sidebar-elems"><div id="rustdoc-modnav"><h2><a href="index.html">In jellytau_<wbr>lib::<wbr>commands::<wbr>auth</a></h2></div></div></nav><div class="sidebar-resizer" title="Drag to resize sidebar"></div><main><div class="width-limiter"><section id="main-content" class="content" tabindex="-1"><div class="main-heading"><div class="rustdoc-breadcrumbs"><a href="../../index.html">jellytau_lib</a>::<wbr><a href="../index.html">commands</a>::<wbr><a href="index.html">auth</a></div><h1>Function <span class="fn">auth_<wbr>get_<wbr>session</span>&nbsp;<button id="copy-path" title="Copy item path to clipboard">Copy item path</button></h1><rustdoc-toolbar></rustdoc-toolbar><span class="sub-heading"><a class="src" href="../../../src/jellytau_lib/commands/auth.rs.html#171-175">Source</a> </span></div><pre class="rust item-decl"><code>pub async fn auth_get_session(
auth_manager: State&lt;'_, <a class="struct" href="struct.AuthManagerWrapper.html" title="struct jellytau_lib::commands::auth::AuthManagerWrapper">AuthManagerWrapper</a>&gt;,
) -&gt; <a class="enum" href="https://doc.rust-lang.org/1.97.1/core/result/enum.Result.html" title="enum core::result::Result">Result</a>&lt;<a class="enum" href="https://doc.rust-lang.org/1.97.1/core/option/enum.Option.html" title="enum core::option::Option">Option</a>&lt;<a class="struct" href="../../auth/struct.Session.html" title="struct jellytau_lib::auth::Session">Session</a>&gt;, <a class="struct" href="https://doc.rust-lang.org/1.97.1/alloc/string/struct.String.html" title="struct alloc::string::String">String</a>&gt;</code></pre><details class="toggle top-doc" open><summary class="hideme"><span>Expand description</span></summary><div class="docblock"><p>Get current session</p>
</div></details></section></div></main></body></html>
@@ -0,0 +1,7 @@
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="Initialize the auth manager (call on app startup) Restores session from storage if available"><title>auth_initialize in jellytau_lib::commands::auth - Rust</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-6b053e98.ttf.woff2,FiraSans-Italic-81dc35de.woff2,FiraSans-Regular-0fe48ade.woff2,FiraSans-MediumItalic-ccf7e434.woff2,FiraSans-Medium-e1aa3f0a.woff2,SourceCodePro-Regular-8badfe75.ttf.woff2,SourceCodePro-Semibold-aa29a496.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2"href="../../../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../../../static.files/normalize-9960930a.css"><link rel="stylesheet" href="../../../static.files/rustdoc-17e0aaed.css"><meta name="rustdoc-vars" data-root-path="../../../" data-static-root-path="../../../static.files/" data-current-crate="jellytau_lib" data-themes="" data-resource-suffix="" data-rustdoc-version="1.97.1 (8bab26f4f 2026-07-14)" data-channel="1.97.1" data-search-js="search-fd9372ac.js" data-stringdex-js="stringdex-2da4960a.js" data-settings-js="settings-170eb4bf.js" ><script src="../../../static.files/storage-41dd4d93.js"></script><script defer src="sidebar-items.js"></script><script defer src="../../../static.files/main-fcd733ba.js"></script><noscript><link rel="stylesheet" href="../../../static.files/noscript-f7c3ffd8.css"></noscript><link rel="alternate icon" type="image/png" href="../../../static.files/favicon-32x32-eab170b8.png"><link rel="icon" type="image/svg+xml" href="../../../static.files/favicon-044be391.svg"></head><body class="rustdoc fn"><a class="skip-main-content" href="#main-content">Skip to main content</a><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><rustdoc-topbar><h2><a href="#">auth_initialize</a></h2></rustdoc-topbar><nav class="sidebar"><div class="sidebar-crate"><h2><a href="../../../jellytau_lib/index.html">jellytau_<wbr>lib</a><span class="version">0.11.1</span></h2></div><div class="sidebar-elems"><div id="rustdoc-modnav"><h2><a href="index.html">In jellytau_<wbr>lib::<wbr>commands::<wbr>auth</a></h2></div></div></nav><div class="sidebar-resizer" title="Drag to resize sidebar"></div><main><div class="width-limiter"><section id="main-content" class="content" tabindex="-1"><div class="main-heading"><div class="rustdoc-breadcrumbs"><a href="../../index.html">jellytau_lib</a>::<wbr><a href="../index.html">commands</a>::<wbr><a href="index.html">auth</a></div><h1>Function <span class="fn">auth_<wbr>initialize</span>&nbsp;<button id="copy-path" title="Copy item path to clipboard">Copy item path</button></h1><rustdoc-toolbar></rustdoc-toolbar><span class="sub-heading"><a class="src" href="../../../src/jellytau_lib/commands/auth.rs.html#20-70">Source</a> </span></div><pre class="rust item-decl"><code>pub async fn auth_initialize(
auth_manager: State&lt;'_, <a class="struct" href="struct.AuthManagerWrapper.html" title="struct jellytau_lib::commands::auth::AuthManagerWrapper">AuthManagerWrapper</a>&gt;,
database: State&lt;'_, <a class="struct" href="../storage/struct.DatabaseWrapper.html" title="struct jellytau_lib::commands::storage::DatabaseWrapper">DatabaseWrapper</a>&gt;,
credentials: State&lt;'_, <a class="struct" href="../storage/struct.CredentialStoreWrapper.html" title="struct jellytau_lib::commands::storage::CredentialStoreWrapper">CredentialStoreWrapper</a>&gt;,
) -&gt; <a class="enum" href="https://doc.rust-lang.org/1.97.1/core/result/enum.Result.html" title="enum core::result::Result">Result</a>&lt;<a class="enum" href="https://doc.rust-lang.org/1.97.1/core/option/enum.Option.html" title="enum core::option::Option">Option</a>&lt;<a class="struct" href="../../auth/struct.Session.html" title="struct jellytau_lib::auth::Session">Session</a>&gt;, <a class="struct" href="https://doc.rust-lang.org/1.97.1/alloc/string/struct.String.html" title="struct alloc::string::String">String</a>&gt;</code></pre><details class="toggle top-doc" open><summary class="hideme"><span>Expand description</span></summary><div class="docblock"><p>Initialize the auth manager (call on app startup)
Restores session from storage if available</p>
</div></details></section></div></main></body></html>
@@ -0,0 +1,8 @@
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="Login with username and password"><title>auth_login in jellytau_lib::commands::auth - Rust</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-6b053e98.ttf.woff2,FiraSans-Italic-81dc35de.woff2,FiraSans-Regular-0fe48ade.woff2,FiraSans-MediumItalic-ccf7e434.woff2,FiraSans-Medium-e1aa3f0a.woff2,SourceCodePro-Regular-8badfe75.ttf.woff2,SourceCodePro-Semibold-aa29a496.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2"href="../../../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../../../static.files/normalize-9960930a.css"><link rel="stylesheet" href="../../../static.files/rustdoc-17e0aaed.css"><meta name="rustdoc-vars" data-root-path="../../../" data-static-root-path="../../../static.files/" data-current-crate="jellytau_lib" data-themes="" data-resource-suffix="" data-rustdoc-version="1.97.1 (8bab26f4f 2026-07-14)" data-channel="1.97.1" data-search-js="search-fd9372ac.js" data-stringdex-js="stringdex-2da4960a.js" data-settings-js="settings-170eb4bf.js" ><script src="../../../static.files/storage-41dd4d93.js"></script><script defer src="sidebar-items.js"></script><script defer src="../../../static.files/main-fcd733ba.js"></script><noscript><link rel="stylesheet" href="../../../static.files/noscript-f7c3ffd8.css"></noscript><link rel="alternate icon" type="image/png" href="../../../static.files/favicon-32x32-eab170b8.png"><link rel="icon" type="image/svg+xml" href="../../../static.files/favicon-044be391.svg"></head><body class="rustdoc fn"><a class="skip-main-content" href="#main-content">Skip to main content</a><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><rustdoc-topbar><h2><a href="#">auth_login</a></h2></rustdoc-topbar><nav class="sidebar"><div class="sidebar-crate"><h2><a href="../../../jellytau_lib/index.html">jellytau_<wbr>lib</a><span class="version">0.11.1</span></h2></div><div class="sidebar-elems"><div id="rustdoc-modnav"><h2><a href="index.html">In jellytau_<wbr>lib::<wbr>commands::<wbr>auth</a></h2></div></div></nav><div class="sidebar-resizer" title="Drag to resize sidebar"></div><main><div class="width-limiter"><section id="main-content" class="content" tabindex="-1"><div class="main-heading"><div class="rustdoc-breadcrumbs"><a href="../../index.html">jellytau_lib</a>::<wbr><a href="../index.html">commands</a>::<wbr><a href="index.html">auth</a></div><h1>Function <span class="fn">auth_<wbr>login</span>&nbsp;<button id="copy-path" title="Copy item path to clipboard">Copy item path</button></h1><rustdoc-toolbar></rustdoc-toolbar><span class="sub-heading"><a class="src" href="../../../src/jellytau_lib/commands/auth.rs.html#85-114">Source</a> </span></div><pre class="rust item-decl"><code>pub async fn auth_login(
server_url: <a class="struct" href="https://doc.rust-lang.org/1.97.1/alloc/string/struct.String.html" title="struct alloc::string::String">String</a>,
username: <a class="struct" href="https://doc.rust-lang.org/1.97.1/alloc/string/struct.String.html" title="struct alloc::string::String">String</a>,
password: <a class="struct" href="https://doc.rust-lang.org/1.97.1/alloc/string/struct.String.html" title="struct alloc::string::String">String</a>,
device_id: <a class="struct" href="https://doc.rust-lang.org/1.97.1/alloc/string/struct.String.html" title="struct alloc::string::String">String</a>,
auth_manager: State&lt;'_, <a class="struct" href="struct.AuthManagerWrapper.html" title="struct jellytau_lib::commands::auth::AuthManagerWrapper">AuthManagerWrapper</a>&gt;,
) -&gt; <a class="enum" href="https://doc.rust-lang.org/1.97.1/core/result/enum.Result.html" title="enum core::result::Result">Result</a>&lt;<a class="struct" href="../../auth/struct.AuthResult.html" title="struct jellytau_lib::auth::AuthResult">AuthResult</a>, <a class="struct" href="https://doc.rust-lang.org/1.97.1/alloc/string/struct.String.html" title="struct alloc::string::String">String</a>&gt;</code></pre><details class="toggle top-doc" open><summary class="hideme"><span>Expand description</span></summary><div class="docblock"><p>Login with username and password</p>
</div></details></section></div></main></body></html>
@@ -0,0 +1,8 @@
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="Logout (clear session and call Jellyfin logout endpoint)"><title>auth_logout in jellytau_lib::commands::auth - Rust</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-6b053e98.ttf.woff2,FiraSans-Italic-81dc35de.woff2,FiraSans-Regular-0fe48ade.woff2,FiraSans-MediumItalic-ccf7e434.woff2,FiraSans-Medium-e1aa3f0a.woff2,SourceCodePro-Regular-8badfe75.ttf.woff2,SourceCodePro-Semibold-aa29a496.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2"href="../../../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../../../static.files/normalize-9960930a.css"><link rel="stylesheet" href="../../../static.files/rustdoc-17e0aaed.css"><meta name="rustdoc-vars" data-root-path="../../../" data-static-root-path="../../../static.files/" data-current-crate="jellytau_lib" data-themes="" data-resource-suffix="" data-rustdoc-version="1.97.1 (8bab26f4f 2026-07-14)" data-channel="1.97.1" data-search-js="search-fd9372ac.js" data-stringdex-js="stringdex-2da4960a.js" data-settings-js="settings-170eb4bf.js" ><script src="../../../static.files/storage-41dd4d93.js"></script><script defer src="sidebar-items.js"></script><script defer src="../../../static.files/main-fcd733ba.js"></script><noscript><link rel="stylesheet" href="../../../static.files/noscript-f7c3ffd8.css"></noscript><link rel="alternate icon" type="image/png" href="../../../static.files/favicon-32x32-eab170b8.png"><link rel="icon" type="image/svg+xml" href="../../../static.files/favicon-044be391.svg"></head><body class="rustdoc fn"><a class="skip-main-content" href="#main-content">Skip to main content</a><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><rustdoc-topbar><h2><a href="#">auth_logout</a></h2></rustdoc-topbar><nav class="sidebar"><div class="sidebar-crate"><h2><a href="../../../jellytau_lib/index.html">jellytau_<wbr>lib</a><span class="version">0.11.1</span></h2></div><div class="sidebar-elems"><div id="rustdoc-modnav"><h2><a href="index.html">In jellytau_<wbr>lib::<wbr>commands::<wbr>auth</a></h2></div></div></nav><div class="sidebar-resizer" title="Drag to resize sidebar"></div><main><div class="width-limiter"><section id="main-content" class="content" tabindex="-1"><div class="main-heading"><div class="rustdoc-breadcrumbs"><a href="../../index.html">jellytau_lib</a>::<wbr><a href="../index.html">commands</a>::<wbr><a href="index.html">auth</a></div><h1>Function <span class="fn">auth_<wbr>logout</span>&nbsp;<button id="copy-path" title="Copy item path to clipboard">Copy item path</button></h1><rustdoc-toolbar></rustdoc-toolbar><span class="sub-heading"><a class="src" href="../../../src/jellytau_lib/commands/auth.rs.html#142-166">Source</a> </span></div><pre class="rust item-decl"><code>pub async fn auth_logout(
server_url: <a class="struct" href="https://doc.rust-lang.org/1.97.1/alloc/string/struct.String.html" title="struct alloc::string::String">String</a>,
access_token: <a class="struct" href="https://doc.rust-lang.org/1.97.1/alloc/string/struct.String.html" title="struct alloc::string::String">String</a>,
device_id: <a class="struct" href="https://doc.rust-lang.org/1.97.1/alloc/string/struct.String.html" title="struct alloc::string::String">String</a>,
auth_manager: State&lt;'_, <a class="struct" href="struct.AuthManagerWrapper.html" title="struct jellytau_lib::commands::auth::AuthManagerWrapper">AuthManagerWrapper</a>&gt;,
session_verifier: State&lt;'_, <a class="struct" href="struct.SessionVerifierWrapper.html" title="struct jellytau_lib::commands::auth::SessionVerifierWrapper">SessionVerifierWrapper</a>&gt;,
) -&gt; <a class="enum" href="https://doc.rust-lang.org/1.97.1/core/result/enum.Result.html" title="enum core::result::Result">Result</a>&lt;<a class="primitive" href="https://doc.rust-lang.org/1.97.1/std/primitive.unit.html">()</a>, <a class="struct" href="https://doc.rust-lang.org/1.97.1/alloc/string/struct.String.html" title="struct alloc::string::String">String</a>&gt;</code></pre><details class="toggle top-doc" open><summary class="hideme"><span>Expand description</span></summary><div class="docblock"><p>Logout (clear session and call Jellyfin logout endpoint)</p>
</div></details></section></div></main></body></html>
@@ -0,0 +1,6 @@
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="Re-authenticate with password (when session expired)"><title>auth_reauthenticate in jellytau_lib::commands::auth - Rust</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-6b053e98.ttf.woff2,FiraSans-Italic-81dc35de.woff2,FiraSans-Regular-0fe48ade.woff2,FiraSans-MediumItalic-ccf7e434.woff2,FiraSans-Medium-e1aa3f0a.woff2,SourceCodePro-Regular-8badfe75.ttf.woff2,SourceCodePro-Semibold-aa29a496.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2"href="../../../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../../../static.files/normalize-9960930a.css"><link rel="stylesheet" href="../../../static.files/rustdoc-17e0aaed.css"><meta name="rustdoc-vars" data-root-path="../../../" data-static-root-path="../../../static.files/" data-current-crate="jellytau_lib" data-themes="" data-resource-suffix="" data-rustdoc-version="1.97.1 (8bab26f4f 2026-07-14)" data-channel="1.97.1" data-search-js="search-fd9372ac.js" data-stringdex-js="stringdex-2da4960a.js" data-settings-js="settings-170eb4bf.js" ><script src="../../../static.files/storage-41dd4d93.js"></script><script defer src="sidebar-items.js"></script><script defer src="../../../static.files/main-fcd733ba.js"></script><noscript><link rel="stylesheet" href="../../../static.files/noscript-f7c3ffd8.css"></noscript><link rel="alternate icon" type="image/png" href="../../../static.files/favicon-32x32-eab170b8.png"><link rel="icon" type="image/svg+xml" href="../../../static.files/favicon-044be391.svg"></head><body class="rustdoc fn"><a class="skip-main-content" href="#main-content">Skip to main content</a><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><rustdoc-topbar><h2><a href="#">auth_reauthenticate</a></h2></rustdoc-topbar><nav class="sidebar"><div class="sidebar-crate"><h2><a href="../../../jellytau_lib/index.html">jellytau_<wbr>lib</a><span class="version">0.11.1</span></h2></div><div class="sidebar-elems"><div id="rustdoc-modnav"><h2><a href="index.html">In jellytau_<wbr>lib::<wbr>commands::<wbr>auth</a></h2></div></div></nav><div class="sidebar-resizer" title="Drag to resize sidebar"></div><main><div class="width-limiter"><section id="main-content" class="content" tabindex="-1"><div class="main-heading"><div class="rustdoc-breadcrumbs"><a href="../../index.html">jellytau_lib</a>::<wbr><a href="../index.html">commands</a>::<wbr><a href="index.html">auth</a></div><h1>Function <span class="fn">auth_<wbr>reauthenticate</span>&nbsp;<button id="copy-path" title="Copy item path to clipboard">Copy item path</button></h1><rustdoc-toolbar></rustdoc-toolbar><span class="sub-heading"><a class="src" href="../../../src/jellytau_lib/commands/auth.rs.html#244-282">Source</a> </span></div><pre class="rust item-decl"><code>pub async fn auth_reauthenticate(
password: <a class="struct" href="https://doc.rust-lang.org/1.97.1/alloc/string/struct.String.html" title="struct alloc::string::String">String</a>,
device_id: <a class="struct" href="https://doc.rust-lang.org/1.97.1/alloc/string/struct.String.html" title="struct alloc::string::String">String</a>,
auth_manager: State&lt;'_, <a class="struct" href="struct.AuthManagerWrapper.html" title="struct jellytau_lib::commands::auth::AuthManagerWrapper">AuthManagerWrapper</a>&gt;,
) -&gt; <a class="enum" href="https://doc.rust-lang.org/1.97.1/core/result/enum.Result.html" title="enum core::result::Result">Result</a>&lt;<a class="struct" href="../../auth/struct.AuthResult.html" title="struct jellytau_lib::auth::AuthResult">AuthResult</a>, <a class="struct" href="https://doc.rust-lang.org/1.97.1/alloc/string/struct.String.html" title="struct alloc::string::String">String</a>&gt;</code></pre><details class="toggle top-doc" open><summary class="hideme"><span>Expand description</span></summary><div class="docblock"><p>Re-authenticate with password (when session expired)</p>
</div></details></section></div></main></body></html>
@@ -0,0 +1,5 @@
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="Set current session (for restoration from storage)"><title>auth_set_session in jellytau_lib::commands::auth - Rust</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-6b053e98.ttf.woff2,FiraSans-Italic-81dc35de.woff2,FiraSans-Regular-0fe48ade.woff2,FiraSans-MediumItalic-ccf7e434.woff2,FiraSans-Medium-e1aa3f0a.woff2,SourceCodePro-Regular-8badfe75.ttf.woff2,SourceCodePro-Semibold-aa29a496.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2"href="../../../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../../../static.files/normalize-9960930a.css"><link rel="stylesheet" href="../../../static.files/rustdoc-17e0aaed.css"><meta name="rustdoc-vars" data-root-path="../../../" data-static-root-path="../../../static.files/" data-current-crate="jellytau_lib" data-themes="" data-resource-suffix="" data-rustdoc-version="1.97.1 (8bab26f4f 2026-07-14)" data-channel="1.97.1" data-search-js="search-fd9372ac.js" data-stringdex-js="stringdex-2da4960a.js" data-settings-js="settings-170eb4bf.js" ><script src="../../../static.files/storage-41dd4d93.js"></script><script defer src="sidebar-items.js"></script><script defer src="../../../static.files/main-fcd733ba.js"></script><noscript><link rel="stylesheet" href="../../../static.files/noscript-f7c3ffd8.css"></noscript><link rel="alternate icon" type="image/png" href="../../../static.files/favicon-32x32-eab170b8.png"><link rel="icon" type="image/svg+xml" href="../../../static.files/favicon-044be391.svg"></head><body class="rustdoc fn"><a class="skip-main-content" href="#main-content">Skip to main content</a><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><rustdoc-topbar><h2><a href="#">auth_set_session</a></h2></rustdoc-topbar><nav class="sidebar"><div class="sidebar-crate"><h2><a href="../../../jellytau_lib/index.html">jellytau_<wbr>lib</a><span class="version">0.11.1</span></h2></div><div class="sidebar-elems"><div id="rustdoc-modnav"><h2><a href="index.html">In jellytau_<wbr>lib::<wbr>commands::<wbr>auth</a></h2></div></div></nav><div class="sidebar-resizer" title="Drag to resize sidebar"></div><main><div class="width-limiter"><section id="main-content" class="content" tabindex="-1"><div class="main-heading"><div class="rustdoc-breadcrumbs"><a href="../../index.html">jellytau_lib</a>::<wbr><a href="../index.html">commands</a>::<wbr><a href="index.html">auth</a></div><h1>Function <span class="fn">auth_<wbr>set_<wbr>session</span>&nbsp;<button id="copy-path" title="Copy item path to clipboard">Copy item path</button></h1><rustdoc-toolbar></rustdoc-toolbar><span class="sub-heading"><a class="src" href="../../../src/jellytau_lib/commands/auth.rs.html#180-195">Source</a> </span></div><pre class="rust item-decl"><code>pub async fn auth_set_session(
session: <a class="enum" href="https://doc.rust-lang.org/1.97.1/core/option/enum.Option.html" title="enum core::option::Option">Option</a>&lt;<a class="struct" href="../../auth/struct.Session.html" title="struct jellytau_lib::auth::Session">Session</a>&gt;,
auth_manager: State&lt;'_, <a class="struct" href="struct.AuthManagerWrapper.html" title="struct jellytau_lib::commands::auth::AuthManagerWrapper">AuthManagerWrapper</a>&gt;,
) -&gt; <a class="enum" href="https://doc.rust-lang.org/1.97.1/core/result/enum.Result.html" title="enum core::result::Result">Result</a>&lt;<a class="primitive" href="https://doc.rust-lang.org/1.97.1/std/primitive.unit.html">()</a>, <a class="struct" href="https://doc.rust-lang.org/1.97.1/alloc/string/struct.String.html" title="struct alloc::string::String">String</a>&gt;</code></pre><details class="toggle top-doc" open><summary class="hideme"><span>Expand description</span></summary><div class="docblock"><p>Set current session (for restoration from storage)</p>
</div></details></section></div></main></body></html>
@@ -0,0 +1,7 @@
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="Start background session verification"><title>auth_start_verification in jellytau_lib::commands::auth - Rust</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-6b053e98.ttf.woff2,FiraSans-Italic-81dc35de.woff2,FiraSans-Regular-0fe48ade.woff2,FiraSans-MediumItalic-ccf7e434.woff2,FiraSans-Medium-e1aa3f0a.woff2,SourceCodePro-Regular-8badfe75.ttf.woff2,SourceCodePro-Semibold-aa29a496.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2"href="../../../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../../../static.files/normalize-9960930a.css"><link rel="stylesheet" href="../../../static.files/rustdoc-17e0aaed.css"><meta name="rustdoc-vars" data-root-path="../../../" data-static-root-path="../../../static.files/" data-current-crate="jellytau_lib" data-themes="" data-resource-suffix="" data-rustdoc-version="1.97.1 (8bab26f4f 2026-07-14)" data-channel="1.97.1" data-search-js="search-fd9372ac.js" data-stringdex-js="stringdex-2da4960a.js" data-settings-js="settings-170eb4bf.js" ><script src="../../../static.files/storage-41dd4d93.js"></script><script defer src="sidebar-items.js"></script><script defer src="../../../static.files/main-fcd733ba.js"></script><noscript><link rel="stylesheet" href="../../../static.files/noscript-f7c3ffd8.css"></noscript><link rel="alternate icon" type="image/png" href="../../../static.files/favicon-32x32-eab170b8.png"><link rel="icon" type="image/svg+xml" href="../../../static.files/favicon-044be391.svg"></head><body class="rustdoc fn"><a class="skip-main-content" href="#main-content">Skip to main content</a><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><rustdoc-topbar><h2><a href="#">auth_start_verification</a></h2></rustdoc-topbar><nav class="sidebar"><div class="sidebar-crate"><h2><a href="../../../jellytau_lib/index.html">jellytau_<wbr>lib</a><span class="version">0.11.1</span></h2></div><div class="sidebar-elems"><div id="rustdoc-modnav"><h2><a href="index.html">In jellytau_<wbr>lib::<wbr>commands::<wbr>auth</a></h2></div></div></nav><div class="sidebar-resizer" title="Drag to resize sidebar"></div><main><div class="width-limiter"><section id="main-content" class="content" tabindex="-1"><div class="main-heading"><div class="rustdoc-breadcrumbs"><a href="../../index.html">jellytau_lib</a>::<wbr><a href="../index.html">commands</a>::<wbr><a href="index.html">auth</a></div><h1>Function <span class="fn">auth_<wbr>start_<wbr>verification</span>&nbsp;<button id="copy-path" title="Copy item path to clipboard">Copy item path</button></h1><rustdoc-toolbar></rustdoc-toolbar><span class="sub-heading"><a class="src" href="../../../src/jellytau_lib/commands/auth.rs.html#200-224">Source</a> </span></div><pre class="rust item-decl"><code>pub async fn auth_start_verification(
device_id: <a class="struct" href="https://doc.rust-lang.org/1.97.1/alloc/string/struct.String.html" title="struct alloc::string::String">String</a>,
app_handle: AppHandle,
auth_manager: State&lt;'_, <a class="struct" href="struct.AuthManagerWrapper.html" title="struct jellytau_lib::commands::auth::AuthManagerWrapper">AuthManagerWrapper</a>&gt;,
session_verifier: State&lt;'_, <a class="struct" href="struct.SessionVerifierWrapper.html" title="struct jellytau_lib::commands::auth::SessionVerifierWrapper">SessionVerifierWrapper</a>&gt;,
) -&gt; <a class="enum" href="https://doc.rust-lang.org/1.97.1/core/result/enum.Result.html" title="enum core::result::Result">Result</a>&lt;<a class="primitive" href="https://doc.rust-lang.org/1.97.1/std/primitive.unit.html">()</a>, <a class="struct" href="https://doc.rust-lang.org/1.97.1/alloc/string/struct.String.html" title="struct alloc::string::String">String</a>&gt;</code></pre><details class="toggle top-doc" open><summary class="hideme"><span>Expand description</span></summary><div class="docblock"><p>Start background session verification</p>
</div></details></section></div></main></body></html>
@@ -0,0 +1,4 @@
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="Stop background session verification"><title>auth_stop_verification in jellytau_lib::commands::auth - Rust</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-6b053e98.ttf.woff2,FiraSans-Italic-81dc35de.woff2,FiraSans-Regular-0fe48ade.woff2,FiraSans-MediumItalic-ccf7e434.woff2,FiraSans-Medium-e1aa3f0a.woff2,SourceCodePro-Regular-8badfe75.ttf.woff2,SourceCodePro-Semibold-aa29a496.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2"href="../../../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../../../static.files/normalize-9960930a.css"><link rel="stylesheet" href="../../../static.files/rustdoc-17e0aaed.css"><meta name="rustdoc-vars" data-root-path="../../../" data-static-root-path="../../../static.files/" data-current-crate="jellytau_lib" data-themes="" data-resource-suffix="" data-rustdoc-version="1.97.1 (8bab26f4f 2026-07-14)" data-channel="1.97.1" data-search-js="search-fd9372ac.js" data-stringdex-js="stringdex-2da4960a.js" data-settings-js="settings-170eb4bf.js" ><script src="../../../static.files/storage-41dd4d93.js"></script><script defer src="sidebar-items.js"></script><script defer src="../../../static.files/main-fcd733ba.js"></script><noscript><link rel="stylesheet" href="../../../static.files/noscript-f7c3ffd8.css"></noscript><link rel="alternate icon" type="image/png" href="../../../static.files/favicon-32x32-eab170b8.png"><link rel="icon" type="image/svg+xml" href="../../../static.files/favicon-044be391.svg"></head><body class="rustdoc fn"><a class="skip-main-content" href="#main-content">Skip to main content</a><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><rustdoc-topbar><h2><a href="#">auth_stop_verification</a></h2></rustdoc-topbar><nav class="sidebar"><div class="sidebar-crate"><h2><a href="../../../jellytau_lib/index.html">jellytau_<wbr>lib</a><span class="version">0.11.1</span></h2></div><div class="sidebar-elems"><div id="rustdoc-modnav"><h2><a href="index.html">In jellytau_<wbr>lib::<wbr>commands::<wbr>auth</a></h2></div></div></nav><div class="sidebar-resizer" title="Drag to resize sidebar"></div><main><div class="width-limiter"><section id="main-content" class="content" tabindex="-1"><div class="main-heading"><div class="rustdoc-breadcrumbs"><a href="../../index.html">jellytau_lib</a>::<wbr><a href="../index.html">commands</a>::<wbr><a href="index.html">auth</a></div><h1>Function <span class="fn">auth_<wbr>stop_<wbr>verification</span>&nbsp;<button id="copy-path" title="Copy item path to clipboard">Copy item path</button></h1><rustdoc-toolbar></rustdoc-toolbar><span class="sub-heading"><a class="src" href="../../../src/jellytau_lib/commands/auth.rs.html#229-239">Source</a> </span></div><pre class="rust item-decl"><code>pub async fn auth_stop_verification(
session_verifier: State&lt;'_, <a class="struct" href="struct.SessionVerifierWrapper.html" title="struct jellytau_lib::commands::auth::SessionVerifierWrapper">SessionVerifierWrapper</a>&gt;,
) -&gt; <a class="enum" href="https://doc.rust-lang.org/1.97.1/core/result/enum.Result.html" title="enum core::result::Result">Result</a>&lt;<a class="primitive" href="https://doc.rust-lang.org/1.97.1/std/primitive.unit.html">()</a>, <a class="struct" href="https://doc.rust-lang.org/1.97.1/alloc/string/struct.String.html" title="struct alloc::string::String">String</a>&gt;</code></pre><details class="toggle top-doc" open><summary class="hideme"><span>Expand description</span></summary><div class="docblock"><p>Stop background session verification</p>
</div></details></section></div></main></body></html>
@@ -0,0 +1,8 @@
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="Verify current session"><title>auth_verify_session in jellytau_lib::commands::auth - Rust</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-6b053e98.ttf.woff2,FiraSans-Italic-81dc35de.woff2,FiraSans-Regular-0fe48ade.woff2,FiraSans-MediumItalic-ccf7e434.woff2,FiraSans-Medium-e1aa3f0a.woff2,SourceCodePro-Regular-8badfe75.ttf.woff2,SourceCodePro-Semibold-aa29a496.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2"href="../../../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../../../static.files/normalize-9960930a.css"><link rel="stylesheet" href="../../../static.files/rustdoc-17e0aaed.css"><meta name="rustdoc-vars" data-root-path="../../../" data-static-root-path="../../../static.files/" data-current-crate="jellytau_lib" data-themes="" data-resource-suffix="" data-rustdoc-version="1.97.1 (8bab26f4f 2026-07-14)" data-channel="1.97.1" data-search-js="search-fd9372ac.js" data-stringdex-js="stringdex-2da4960a.js" data-settings-js="settings-170eb4bf.js" ><script src="../../../static.files/storage-41dd4d93.js"></script><script defer src="sidebar-items.js"></script><script defer src="../../../static.files/main-fcd733ba.js"></script><noscript><link rel="stylesheet" href="../../../static.files/noscript-f7c3ffd8.css"></noscript><link rel="alternate icon" type="image/png" href="../../../static.files/favicon-32x32-eab170b8.png"><link rel="icon" type="image/svg+xml" href="../../../static.files/favicon-044be391.svg"></head><body class="rustdoc fn"><a class="skip-main-content" href="#main-content">Skip to main content</a><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><rustdoc-topbar><h2><a href="#">auth_verify_session</a></h2></rustdoc-topbar><nav class="sidebar"><div class="sidebar-crate"><h2><a href="../../../jellytau_lib/index.html">jellytau_<wbr>lib</a><span class="version">0.11.1</span></h2></div><div class="sidebar-elems"><div id="rustdoc-modnav"><h2><a href="index.html">In jellytau_<wbr>lib::<wbr>commands::<wbr>auth</a></h2></div></div></nav><div class="sidebar-resizer" title="Drag to resize sidebar"></div><main><div class="width-limiter"><section id="main-content" class="content" tabindex="-1"><div class="main-heading"><div class="rustdoc-breadcrumbs"><a href="../../index.html">jellytau_lib</a>::<wbr><a href="../index.html">commands</a>::<wbr><a href="index.html">auth</a></div><h1>Function <span class="fn">auth_<wbr>verify_<wbr>session</span>&nbsp;<button id="copy-path" title="Copy item path to clipboard">Copy item path</button></h1><rustdoc-toolbar></rustdoc-toolbar><span class="sub-heading"><a class="src" href="../../../src/jellytau_lib/commands/auth.rs.html#119-137">Source</a> </span></div><pre class="rust item-decl"><code>pub async fn auth_verify_session(
server_url: <a class="struct" href="https://doc.rust-lang.org/1.97.1/alloc/string/struct.String.html" title="struct alloc::string::String">String</a>,
user_id: <a class="struct" href="https://doc.rust-lang.org/1.97.1/alloc/string/struct.String.html" title="struct alloc::string::String">String</a>,
access_token: <a class="struct" href="https://doc.rust-lang.org/1.97.1/alloc/string/struct.String.html" title="struct alloc::string::String">String</a>,
device_id: <a class="struct" href="https://doc.rust-lang.org/1.97.1/alloc/string/struct.String.html" title="struct alloc::string::String">String</a>,
auth_manager: State&lt;'_, <a class="struct" href="struct.AuthManagerWrapper.html" title="struct jellytau_lib::commands::auth::AuthManagerWrapper">AuthManagerWrapper</a>&gt;,
) -&gt; <a class="enum" href="https://doc.rust-lang.org/1.97.1/core/result/enum.Result.html" title="enum core::result::Result">Result</a>&lt;<a class="primitive" href="https://doc.rust-lang.org/1.97.1/std/primitive.bool.html">bool</a>, <a class="struct" href="https://doc.rust-lang.org/1.97.1/alloc/string/struct.String.html" title="struct alloc::string::String">String</a>&gt;</code></pre><details class="toggle top-doc" open><summary class="hideme"><span>Expand description</span></summary><div class="docblock"><p>Verify current session</p>
</div></details></section></div></main></body></html>
@@ -0,0 +1,4 @@
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="Authentication and session-lifecycle commands."><title>jellytau_lib::commands::auth - Rust</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-6b053e98.ttf.woff2,FiraSans-Italic-81dc35de.woff2,FiraSans-Regular-0fe48ade.woff2,FiraSans-MediumItalic-ccf7e434.woff2,FiraSans-Medium-e1aa3f0a.woff2,SourceCodePro-Regular-8badfe75.ttf.woff2,SourceCodePro-Semibold-aa29a496.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2"href="../../../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../../../static.files/normalize-9960930a.css"><link rel="stylesheet" href="../../../static.files/rustdoc-17e0aaed.css"><meta name="rustdoc-vars" data-root-path="../../../" data-static-root-path="../../../static.files/" data-current-crate="jellytau_lib" data-themes="" data-resource-suffix="" data-rustdoc-version="1.97.1 (8bab26f4f 2026-07-14)" data-channel="1.97.1" data-search-js="search-fd9372ac.js" data-stringdex-js="stringdex-2da4960a.js" data-settings-js="settings-170eb4bf.js" ><script src="../../../static.files/storage-41dd4d93.js"></script><script defer src="../sidebar-items.js"></script><script defer src="../../../static.files/main-fcd733ba.js"></script><noscript><link rel="stylesheet" href="../../../static.files/noscript-f7c3ffd8.css"></noscript><link rel="alternate icon" type="image/png" href="../../../static.files/favicon-32x32-eab170b8.png"><link rel="icon" type="image/svg+xml" href="../../../static.files/favicon-044be391.svg"></head><body class="rustdoc mod"><a class="skip-main-content" href="#main-content">Skip to main content</a><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><rustdoc-topbar><h2><a href="#">Module auth</a></h2></rustdoc-topbar><nav class="sidebar"><div class="sidebar-crate"><h2><a href="../../../jellytau_lib/index.html">jellytau_<wbr>lib</a><span class="version">0.11.1</span></h2></div><div class="sidebar-elems"><section id="rustdoc-toc"><h2 class="location"><a href="#">Module auth</a></h2><h3><a href="#structs">Module Items</a></h3><ul class="block"><li><a href="#structs" title="Structs">Structs</a></li><li><a href="#functions" title="Functions">Functions</a></li></ul></section><div id="rustdoc-modnav"><h2><a href="../index.html">In jellytau_<wbr>lib::<wbr>commands</a></h2></div></div></nav><div class="sidebar-resizer" title="Drag to resize sidebar"></div><main><div class="width-limiter"><section id="main-content" class="content" tabindex="-1"><div class="main-heading"><div class="rustdoc-breadcrumbs"><a href="../../index.html">jellytau_lib</a>::<wbr><a href="../index.html">commands</a></div><h1>Module <span>auth</span>&nbsp;<button id="copy-path" title="Copy item path to clipboard">Copy item path</button></h1><rustdoc-toolbar></rustdoc-toolbar><span class="sub-heading"><a class="src" href="../../../src/jellytau_lib/commands/auth.rs.html#1-476">Source</a> </span></div><details class="toggle top-doc" open><summary class="hideme"><span>Expand description</span></summary><div class="docblock"><p>Authentication and session-lifecycle commands.</p>
<p>TRACES: UR-042 | IR-009, IR-014, JA-002 | DR-054</p>
</div></details><h2 id="structs" class="section-header">Structs<a href="#structs" class="anchor">§</a></h2><dl class="item-table"><dt><a class="struct" href="struct.AuthManagerWrapper.html" title="struct jellytau_lib::commands::auth::AuthManagerWrapper">Auth<wbr>Manager<wbr>Wrapper</a></dt><dd>Wrapper for AuthManager to manage in Tauri state</dd><dt><a class="struct" href="struct.SessionVerifierWrapper.html" title="struct jellytau_lib::commands::auth::SessionVerifierWrapper">Session<wbr>Verifier<wbr>Wrapper</a></dt><dd>Wrapper for SessionVerifier to manage in Tauri state</dd></dl><h2 id="functions" class="section-header">Functions<a href="#functions" class="anchor">§</a></h2><dl class="item-table"><dt><a class="fn" href="fn.auth_connect_to_server.html" title="fn jellytau_lib::commands::auth::auth_connect_to_server">auth_<wbr>connect_<wbr>to_<wbr>server</a></dt><dd>Connect to a Jellyfin server and get server info</dd><dt><a class="fn" href="fn.auth_get_session.html" title="fn jellytau_lib::commands::auth::auth_get_session">auth_<wbr>get_<wbr>session</a></dt><dd>Get current session</dd><dt><a class="fn" href="fn.auth_initialize.html" title="fn jellytau_lib::commands::auth::auth_initialize">auth_<wbr>initialize</a></dt><dd>Initialize the auth manager (call on app startup)
Restores session from storage if available</dd><dt><a class="fn" href="fn.auth_login.html" title="fn jellytau_lib::commands::auth::auth_login">auth_<wbr>login</a></dt><dd>Login with username and password</dd><dt><a class="fn" href="fn.auth_logout.html" title="fn jellytau_lib::commands::auth::auth_logout">auth_<wbr>logout</a></dt><dd>Logout (clear session and call Jellyfin logout endpoint)</dd><dt><a class="fn" href="fn.auth_reauthenticate.html" title="fn jellytau_lib::commands::auth::auth_reauthenticate">auth_<wbr>reauthenticate</a></dt><dd>Re-authenticate with password (when session expired)</dd><dt><a class="fn" href="fn.auth_set_session.html" title="fn jellytau_lib::commands::auth::auth_set_session">auth_<wbr>set_<wbr>session</a></dt><dd>Set current session (for restoration from storage)</dd><dt><a class="fn" href="fn.auth_start_verification.html" title="fn jellytau_lib::commands::auth::auth_start_verification">auth_<wbr>start_<wbr>verification</a></dt><dd>Start background session verification</dd><dt><a class="fn" href="fn.auth_stop_verification.html" title="fn jellytau_lib::commands::auth::auth_stop_verification">auth_<wbr>stop_<wbr>verification</a></dt><dd>Stop background session verification</dd><dt><a class="fn" href="fn.auth_verify_session.html" title="fn jellytau_lib::commands::auth::auth_verify_session">auth_<wbr>verify_<wbr>session</a></dt><dd>Verify current session</dd></dl></section></div></main></body></html>
@@ -0,0 +1 @@
window.SIDEBAR_ITEMS = {"fn":["auth_connect_to_server","auth_get_session","auth_initialize","auth_login","auth_logout","auth_reauthenticate","auth_set_session","auth_start_verification","auth_stop_verification","auth_verify_session"],"struct":["AuthManagerWrapper","SessionVerifierWrapper"]};
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -0,0 +1,2 @@
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="Kebab-case, per the projects event convention."><title>CATALOG_INDEX_EVENT in jellytau_lib::commands::catalog - Rust</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-6b053e98.ttf.woff2,FiraSans-Italic-81dc35de.woff2,FiraSans-Regular-0fe48ade.woff2,FiraSans-MediumItalic-ccf7e434.woff2,FiraSans-Medium-e1aa3f0a.woff2,SourceCodePro-Regular-8badfe75.ttf.woff2,SourceCodePro-Semibold-aa29a496.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2"href="../../../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../../../static.files/normalize-9960930a.css"><link rel="stylesheet" href="../../../static.files/rustdoc-17e0aaed.css"><meta name="rustdoc-vars" data-root-path="../../../" data-static-root-path="../../../static.files/" data-current-crate="jellytau_lib" data-themes="" data-resource-suffix="" data-rustdoc-version="1.97.1 (8bab26f4f 2026-07-14)" data-channel="1.97.1" data-search-js="search-fd9372ac.js" data-stringdex-js="stringdex-2da4960a.js" data-settings-js="settings-170eb4bf.js" ><script src="../../../static.files/storage-41dd4d93.js"></script><script defer src="sidebar-items.js"></script><script defer src="../../../static.files/main-fcd733ba.js"></script><noscript><link rel="stylesheet" href="../../../static.files/noscript-f7c3ffd8.css"></noscript><link rel="alternate icon" type="image/png" href="../../../static.files/favicon-32x32-eab170b8.png"><link rel="icon" type="image/svg+xml" href="../../../static.files/favicon-044be391.svg"></head><body class="rustdoc constant"><a class="skip-main-content" href="#main-content">Skip to main content</a><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><rustdoc-topbar><h2><a href="#">CATALOG_INDEX_EVENT</a></h2></rustdoc-topbar><nav class="sidebar"><div class="sidebar-crate"><h2><a href="../../../jellytau_lib/index.html">jellytau_<wbr>lib</a><span class="version">0.11.1</span></h2></div><div class="sidebar-elems"><div id="rustdoc-modnav"><h2><a href="index.html">In jellytau_<wbr>lib::<wbr>commands::<wbr>catalog</a></h2></div></div></nav><div class="sidebar-resizer" title="Drag to resize sidebar"></div><main><div class="width-limiter"><section id="main-content" class="content" tabindex="-1"><div class="main-heading"><div class="rustdoc-breadcrumbs"><a href="../../index.html">jellytau_lib</a>::<wbr><a href="../index.html">commands</a>::<wbr><a href="index.html">catalog</a></div><h1>Constant <span class="constant">CATALOG_<wbr>INDEX_<wbr>EVENT</span>&nbsp;<button id="copy-path" title="Copy item path to clipboard">Copy item path</button></h1><rustdoc-toolbar></rustdoc-toolbar><span class="sub-heading"><a class="src" href="../../../src/jellytau_lib/commands/catalog.rs.html#57">Source</a> </span></div><pre class="rust item-decl"><code>pub const CATALOG_INDEX_EVENT: &amp;<a class="primitive" href="https://doc.rust-lang.org/1.97.1/std/primitive.str.html">str</a> = &quot;catalog-index-event&quot;;</code></pre><details class="toggle top-doc" open><summary class="hideme"><span>Expand description</span></summary><div class="docblock"><p>Kebab-case, per the projects event convention.</p>
</div></details></section></div></main></body></html>
@@ -0,0 +1,5 @@
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="Delay before the first staleness check, to let sign-in complete and the repository be registered. Without it the first check runs against an empty repository manager and a fresh install would sit unindexed until the next tick."><title>CATALOG_INDEX_FIRST_CHECK in jellytau_lib::commands::catalog - Rust</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-6b053e98.ttf.woff2,FiraSans-Italic-81dc35de.woff2,FiraSans-Regular-0fe48ade.woff2,FiraSans-MediumItalic-ccf7e434.woff2,FiraSans-Medium-e1aa3f0a.woff2,SourceCodePro-Regular-8badfe75.ttf.woff2,SourceCodePro-Semibold-aa29a496.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2"href="../../../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../../../static.files/normalize-9960930a.css"><link rel="stylesheet" href="../../../static.files/rustdoc-17e0aaed.css"><meta name="rustdoc-vars" data-root-path="../../../" data-static-root-path="../../../static.files/" data-current-crate="jellytau_lib" data-themes="" data-resource-suffix="" data-rustdoc-version="1.97.1 (8bab26f4f 2026-07-14)" data-channel="1.97.1" data-search-js="search-fd9372ac.js" data-stringdex-js="stringdex-2da4960a.js" data-settings-js="settings-170eb4bf.js" ><script src="../../../static.files/storage-41dd4d93.js"></script><script defer src="sidebar-items.js"></script><script defer src="../../../static.files/main-fcd733ba.js"></script><noscript><link rel="stylesheet" href="../../../static.files/noscript-f7c3ffd8.css"></noscript><link rel="alternate icon" type="image/png" href="../../../static.files/favicon-32x32-eab170b8.png"><link rel="icon" type="image/svg+xml" href="../../../static.files/favicon-044be391.svg"></head><body class="rustdoc constant"><a class="skip-main-content" href="#main-content">Skip to main content</a><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><rustdoc-topbar><h2><a href="#">CATALOG_INDEX_FIRST_CHECK</a></h2></rustdoc-topbar><nav class="sidebar"><div class="sidebar-crate"><h2><a href="../../../jellytau_lib/index.html">jellytau_<wbr>lib</a><span class="version">0.11.1</span></h2></div><div class="sidebar-elems"><div id="rustdoc-modnav"><h2><a href="index.html">In jellytau_<wbr>lib::<wbr>commands::<wbr>catalog</a></h2></div></div></nav><div class="sidebar-resizer" title="Drag to resize sidebar"></div><main><div class="width-limiter"><section id="main-content" class="content" tabindex="-1"><div class="main-heading"><div class="rustdoc-breadcrumbs"><a href="../../index.html">jellytau_lib</a>::<wbr><a href="../index.html">commands</a>::<wbr><a href="index.html">catalog</a></div><h1>Constant <span class="constant">CATALOG_<wbr>INDEX_<wbr>FIRST_<wbr>CHECK</span>&nbsp;<button id="copy-path" title="Copy item path to clipboard">Copy item path</button></h1><rustdoc-toolbar></rustdoc-toolbar><span class="sub-heading"><a class="src" href="../../../src/jellytau_lib/commands/catalog.rs.html#54">Source</a> </span></div><pre class="rust item-decl"><code>const CATALOG_INDEX_FIRST_CHECK: <a class="struct" href="https://doc.rust-lang.org/1.97.1/core/time/struct.Duration.html" title="struct core::time::Duration">Duration</a>;</code></pre><details class="toggle top-doc" open><summary class="hideme"><span>Expand description</span></summary><div class="docblock"><p>Delay before the first staleness check, to let sign-in complete and the
repository be registered. Without it the first check runs against an empty
repository manager and a fresh install would sit unindexed until the next
tick.</p>
</div></details></section></div></main></body></html>
@@ -0,0 +1,6 @@
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="How often the scheduler wakes to check staleness. Far shorter than the TTL because a tick is nearly free — one indexed `app_settings` lookup — and it is what makes the indexer responsive to events it cannot subscribe to: signing in, and coming back online. The TTL, not the tick, decides whether a crawl actually happens."><title>CATALOG_INDEX_TICK in jellytau_lib::commands::catalog - Rust</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-6b053e98.ttf.woff2,FiraSans-Italic-81dc35de.woff2,FiraSans-Regular-0fe48ade.woff2,FiraSans-MediumItalic-ccf7e434.woff2,FiraSans-Medium-e1aa3f0a.woff2,SourceCodePro-Regular-8badfe75.ttf.woff2,SourceCodePro-Semibold-aa29a496.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2"href="../../../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../../../static.files/normalize-9960930a.css"><link rel="stylesheet" href="../../../static.files/rustdoc-17e0aaed.css"><meta name="rustdoc-vars" data-root-path="../../../" data-static-root-path="../../../static.files/" data-current-crate="jellytau_lib" data-themes="" data-resource-suffix="" data-rustdoc-version="1.97.1 (8bab26f4f 2026-07-14)" data-channel="1.97.1" data-search-js="search-fd9372ac.js" data-stringdex-js="stringdex-2da4960a.js" data-settings-js="settings-170eb4bf.js" ><script src="../../../static.files/storage-41dd4d93.js"></script><script defer src="sidebar-items.js"></script><script defer src="../../../static.files/main-fcd733ba.js"></script><noscript><link rel="stylesheet" href="../../../static.files/noscript-f7c3ffd8.css"></noscript><link rel="alternate icon" type="image/png" href="../../../static.files/favicon-32x32-eab170b8.png"><link rel="icon" type="image/svg+xml" href="../../../static.files/favicon-044be391.svg"></head><body class="rustdoc constant"><a class="skip-main-content" href="#main-content">Skip to main content</a><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><rustdoc-topbar><h2><a href="#">CATALOG_INDEX_TICK</a></h2></rustdoc-topbar><nav class="sidebar"><div class="sidebar-crate"><h2><a href="../../../jellytau_lib/index.html">jellytau_<wbr>lib</a><span class="version">0.11.1</span></h2></div><div class="sidebar-elems"><div id="rustdoc-modnav"><h2><a href="index.html">In jellytau_<wbr>lib::<wbr>commands::<wbr>catalog</a></h2></div></div></nav><div class="sidebar-resizer" title="Drag to resize sidebar"></div><main><div class="width-limiter"><section id="main-content" class="content" tabindex="-1"><div class="main-heading"><div class="rustdoc-breadcrumbs"><a href="../../index.html">jellytau_lib</a>::<wbr><a href="../index.html">commands</a>::<wbr><a href="index.html">catalog</a></div><h1>Constant <span class="constant">CATALOG_<wbr>INDEX_<wbr>TICK</span>&nbsp;<button id="copy-path" title="Copy item path to clipboard">Copy item path</button></h1><rustdoc-toolbar></rustdoc-toolbar><span class="sub-heading"><a class="src" href="../../../src/jellytau_lib/commands/catalog.rs.html#48">Source</a> </span></div><pre class="rust item-decl"><code>const CATALOG_INDEX_TICK: <a class="struct" href="https://doc.rust-lang.org/1.97.1/core/time/struct.Duration.html" title="struct core::time::Duration">Duration</a>;</code></pre><details class="toggle top-doc" open><summary class="hideme"><span>Expand description</span></summary><div class="docblock"><p>How often the scheduler wakes to <em>check</em> staleness. Far shorter than the TTL
because a tick is nearly free — one indexed <code>app_settings</code> lookup — and it is
what makes the indexer responsive to events it cannot subscribe to: signing
in, and coming back online. The TTL, not the tick, decides whether a crawl
actually happens.</p>
</div></details></section></div></main></body></html>
@@ -0,0 +1,7 @@
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="How long an index stays fresh before a re-index is due."><title>CATALOG_INDEX_TTL in jellytau_lib::commands::catalog - Rust</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-6b053e98.ttf.woff2,FiraSans-Italic-81dc35de.woff2,FiraSans-Regular-0fe48ade.woff2,FiraSans-MediumItalic-ccf7e434.woff2,FiraSans-Medium-e1aa3f0a.woff2,SourceCodePro-Regular-8badfe75.ttf.woff2,SourceCodePro-Semibold-aa29a496.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2"href="../../../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../../../static.files/normalize-9960930a.css"><link rel="stylesheet" href="../../../static.files/rustdoc-17e0aaed.css"><meta name="rustdoc-vars" data-root-path="../../../" data-static-root-path="../../../static.files/" data-current-crate="jellytau_lib" data-themes="" data-resource-suffix="" data-rustdoc-version="1.97.1 (8bab26f4f 2026-07-14)" data-channel="1.97.1" data-search-js="search-fd9372ac.js" data-stringdex-js="stringdex-2da4960a.js" data-settings-js="settings-170eb4bf.js" ><script src="../../../static.files/storage-41dd4d93.js"></script><script defer src="sidebar-items.js"></script><script defer src="../../../static.files/main-fcd733ba.js"></script><noscript><link rel="stylesheet" href="../../../static.files/noscript-f7c3ffd8.css"></noscript><link rel="alternate icon" type="image/png" href="../../../static.files/favicon-32x32-eab170b8.png"><link rel="icon" type="image/svg+xml" href="../../../static.files/favicon-044be391.svg"></head><body class="rustdoc constant"><a class="skip-main-content" href="#main-content">Skip to main content</a><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><rustdoc-topbar><h2><a href="#">CATALOG_INDEX_TTL</a></h2></rustdoc-topbar><nav class="sidebar"><div class="sidebar-crate"><h2><a href="../../../jellytau_lib/index.html">jellytau_<wbr>lib</a><span class="version">0.11.1</span></h2></div><div class="sidebar-elems"><div id="rustdoc-modnav"><h2><a href="index.html">In jellytau_<wbr>lib::<wbr>commands::<wbr>catalog</a></h2></div></div></nav><div class="sidebar-resizer" title="Drag to resize sidebar"></div><main><div class="width-limiter"><section id="main-content" class="content" tabindex="-1"><div class="main-heading"><div class="rustdoc-breadcrumbs"><a href="../../index.html">jellytau_lib</a>::<wbr><a href="../index.html">commands</a>::<wbr><a href="index.html">catalog</a></div><h1>Constant <span class="constant">CATALOG_<wbr>INDEX_<wbr>TTL</span>&nbsp;<button id="copy-path" title="Copy item path to clipboard">Copy item path</button></h1><rustdoc-toolbar></rustdoc-toolbar><span class="sub-heading"><a class="src" href="../../../src/jellytau_lib/commands/catalog.rs.html#41">Source</a> </span></div><pre class="rust item-decl"><code>const CATALOG_INDEX_TTL: <a class="struct" href="https://doc.rust-lang.org/1.97.1/core/time/struct.Duration.html" title="struct core::time::Duration">Duration</a>;</code></pre><details class="toggle top-doc" open><summary class="hideme"><span>Expand description</span></summary><div class="docblock"><p>How long an index stays fresh before a re-index is due.</p>
<p>This lives in Rust rather than being a frontend constant because it decides
<em>whether the local cache is authoritative</em> — the same class of decision as
<code>include_catalog_browse</code>, and squarely the “sync policy” the spec review
checklist keeps out of the presentation layer. If it later becomes
user-configurable it stays a Rust-owned setting edited through a command.</p>
</div></details></section></div></main></body></html>
@@ -0,0 +1,9 @@
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="Item types worth caching for offline browsing: containers the library landing pages render plus the playable leaves users queue for download. `MusicArtist` and `Playlist` are here because search groups results by them (UR-060s Artists group). Without them in the crawl, the local index can never answer an artist query and those groups can only ever be filled by the server leg. Keep this in step with what `prune_stale_catalog` is allowed to sweep — the crawl is only authoritative for the types it asks for."><title>CATALOG_ITEM_TYPES in jellytau_lib::commands::catalog - Rust</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-6b053e98.ttf.woff2,FiraSans-Italic-81dc35de.woff2,FiraSans-Regular-0fe48ade.woff2,FiraSans-MediumItalic-ccf7e434.woff2,FiraSans-Medium-e1aa3f0a.woff2,SourceCodePro-Regular-8badfe75.ttf.woff2,SourceCodePro-Semibold-aa29a496.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2"href="../../../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../../../static.files/normalize-9960930a.css"><link rel="stylesheet" href="../../../static.files/rustdoc-17e0aaed.css"><meta name="rustdoc-vars" data-root-path="../../../" data-static-root-path="../../../static.files/" data-current-crate="jellytau_lib" data-themes="" data-resource-suffix="" data-rustdoc-version="1.97.1 (8bab26f4f 2026-07-14)" data-channel="1.97.1" data-search-js="search-fd9372ac.js" data-stringdex-js="stringdex-2da4960a.js" data-settings-js="settings-170eb4bf.js" ><script src="../../../static.files/storage-41dd4d93.js"></script><script defer src="sidebar-items.js"></script><script defer src="../../../static.files/main-fcd733ba.js"></script><noscript><link rel="stylesheet" href="../../../static.files/noscript-f7c3ffd8.css"></noscript><link rel="alternate icon" type="image/png" href="../../../static.files/favicon-32x32-eab170b8.png"><link rel="icon" type="image/svg+xml" href="../../../static.files/favicon-044be391.svg"></head><body class="rustdoc constant"><a class="skip-main-content" href="#main-content">Skip to main content</a><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><rustdoc-topbar><h2><a href="#">CATALOG_ITEM_TYPES</a></h2></rustdoc-topbar><nav class="sidebar"><div class="sidebar-crate"><h2><a href="../../../jellytau_lib/index.html">jellytau_<wbr>lib</a><span class="version">0.11.1</span></h2></div><div class="sidebar-elems"><div id="rustdoc-modnav"><h2><a href="index.html">In jellytau_<wbr>lib::<wbr>commands::<wbr>catalog</a></h2></div></div></nav><div class="sidebar-resizer" title="Drag to resize sidebar"></div><main><div class="width-limiter"><section id="main-content" class="content" tabindex="-1"><div class="main-heading"><div class="rustdoc-breadcrumbs"><a href="../../index.html">jellytau_lib</a>::<wbr><a href="../index.html">commands</a>::<wbr><a href="index.html">catalog</a></div><h1>Constant <span class="constant">CATALOG_<wbr>ITEM_<wbr>TYPES</span>&nbsp;<button id="copy-path" title="Copy item path to clipboard">Copy item path</button></h1><rustdoc-toolbar></rustdoc-toolbar><span class="sub-heading"><a class="src" href="../../../src/jellytau_lib/commands/catalog.rs.html#97-107">Source</a> </span></div><pre class="rust item-decl"><code>const CATALOG_ITEM_TYPES: &amp;[&amp;<a class="primitive" href="https://doc.rust-lang.org/1.97.1/std/primitive.str.html">str</a>];</code></pre><details class="toggle top-doc" open><summary class="hideme"><span>Expand description</span></summary><div class="docblock"><p>Item types worth caching for offline browsing: containers the library
landing pages render plus the playable leaves users queue for download.
<code>MusicArtist</code> and <code>Playlist</code> are here because search groups results by them
(UR-060s Artists group). Without them in the crawl, the local index can
never answer an artist query and those groups can only ever be filled by the
server leg. Keep this in step with what <code>prune_stale_catalog</code> is allowed to
sweep — the crawl is only authoritative for the types it asks for.</p>
<p>TRACES: UR-065, UR-060 | DR-111</p>
</div></details></section></div></main></body></html>
@@ -0,0 +1,3 @@
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="app_settings key holding the RFC-3339 timestamp of the last successful full-catalog sync."><title>LAST_CATALOG_SYNC_KEY in jellytau_lib::commands::catalog - Rust</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-6b053e98.ttf.woff2,FiraSans-Italic-81dc35de.woff2,FiraSans-Regular-0fe48ade.woff2,FiraSans-MediumItalic-ccf7e434.woff2,FiraSans-Medium-e1aa3f0a.woff2,SourceCodePro-Regular-8badfe75.ttf.woff2,SourceCodePro-Semibold-aa29a496.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2"href="../../../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../../../static.files/normalize-9960930a.css"><link rel="stylesheet" href="../../../static.files/rustdoc-17e0aaed.css"><meta name="rustdoc-vars" data-root-path="../../../" data-static-root-path="../../../static.files/" data-current-crate="jellytau_lib" data-themes="" data-resource-suffix="" data-rustdoc-version="1.97.1 (8bab26f4f 2026-07-14)" data-channel="1.97.1" data-search-js="search-fd9372ac.js" data-stringdex-js="stringdex-2da4960a.js" data-settings-js="settings-170eb4bf.js" ><script src="../../../static.files/storage-41dd4d93.js"></script><script defer src="sidebar-items.js"></script><script defer src="../../../static.files/main-fcd733ba.js"></script><noscript><link rel="stylesheet" href="../../../static.files/noscript-f7c3ffd8.css"></noscript><link rel="alternate icon" type="image/png" href="../../../static.files/favicon-32x32-eab170b8.png"><link rel="icon" type="image/svg+xml" href="../../../static.files/favicon-044be391.svg"></head><body class="rustdoc constant"><a class="skip-main-content" href="#main-content">Skip to main content</a><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><rustdoc-topbar><h2><a href="#">LAST_CATALOG_SYNC_KEY</a></h2></rustdoc-topbar><nav class="sidebar"><div class="sidebar-crate"><h2><a href="../../../jellytau_lib/index.html">jellytau_<wbr>lib</a><span class="version">0.11.1</span></h2></div><div class="sidebar-elems"><div id="rustdoc-modnav"><h2><a href="index.html">In jellytau_<wbr>lib::<wbr>commands::<wbr>catalog</a></h2></div></div></nav><div class="sidebar-resizer" title="Drag to resize sidebar"></div><main><div class="width-limiter"><section id="main-content" class="content" tabindex="-1"><div class="main-heading"><div class="rustdoc-breadcrumbs"><a href="../../index.html">jellytau_lib</a>::<wbr><a href="../index.html">commands</a>::<wbr><a href="index.html">catalog</a></div><h1>Constant <span class="constant">LAST_<wbr>CATALOG_<wbr>SYNC_<wbr>KEY</span>&nbsp;<button id="copy-path" title="Copy item path to clipboard">Copy item path</button></h1><rustdoc-toolbar></rustdoc-toolbar><span class="sub-heading"><a class="src" href="../../../src/jellytau_lib/commands/catalog.rs.html#32">Source</a> </span></div><pre class="rust item-decl"><code>const LAST_CATALOG_SYNC_KEY: &amp;<a class="primitive" href="https://doc.rust-lang.org/1.97.1/std/primitive.str.html">str</a> = &quot;last_catalog_sync&quot;;</code></pre><details class="toggle top-doc" open><summary class="hideme"><span>Expand description</span></summary><div class="docblock"><p>app_settings key holding the RFC-3339 timestamp of the last successful
full-catalog sync.</p>
</div></details></section></div></main></body></html>
@@ -0,0 +1,6 @@
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="Jellyfin item types whose download is a video stream rather than an audio one. The download queue stores an opaque `media_type` (audio/video); this is where the taxonomy that produces it lives, so the frontend never has to know which item types are video."><title>VIDEO_ITEM_TYPES in jellytau_lib::commands::catalog - Rust</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-6b053e98.ttf.woff2,FiraSans-Italic-81dc35de.woff2,FiraSans-Regular-0fe48ade.woff2,FiraSans-MediumItalic-ccf7e434.woff2,FiraSans-Medium-e1aa3f0a.woff2,SourceCodePro-Regular-8badfe75.ttf.woff2,SourceCodePro-Semibold-aa29a496.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2"href="../../../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../../../static.files/normalize-9960930a.css"><link rel="stylesheet" href="../../../static.files/rustdoc-17e0aaed.css"><meta name="rustdoc-vars" data-root-path="../../../" data-static-root-path="../../../static.files/" data-current-crate="jellytau_lib" data-themes="" data-resource-suffix="" data-rustdoc-version="1.97.1 (8bab26f4f 2026-07-14)" data-channel="1.97.1" data-search-js="search-fd9372ac.js" data-stringdex-js="stringdex-2da4960a.js" data-settings-js="settings-170eb4bf.js" ><script src="../../../static.files/storage-41dd4d93.js"></script><script defer src="sidebar-items.js"></script><script defer src="../../../static.files/main-fcd733ba.js"></script><noscript><link rel="stylesheet" href="../../../static.files/noscript-f7c3ffd8.css"></noscript><link rel="alternate icon" type="image/png" href="../../../static.files/favicon-32x32-eab170b8.png"><link rel="icon" type="image/svg+xml" href="../../../static.files/favicon-044be391.svg"></head><body class="rustdoc constant"><a class="skip-main-content" href="#main-content">Skip to main content</a><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><rustdoc-topbar><h2><a href="#">VIDEO_ITEM_TYPES</a></h2></rustdoc-topbar><nav class="sidebar"><div class="sidebar-crate"><h2><a href="../../../jellytau_lib/index.html">jellytau_<wbr>lib</a><span class="version">0.11.1</span></h2></div><div class="sidebar-elems"><div id="rustdoc-modnav"><h2><a href="index.html">In jellytau_<wbr>lib::<wbr>commands::<wbr>catalog</a></h2></div></div></nav><div class="sidebar-resizer" title="Drag to resize sidebar"></div><main><div class="width-limiter"><section id="main-content" class="content" tabindex="-1"><div class="main-heading"><div class="rustdoc-breadcrumbs"><a href="../../index.html">jellytau_lib</a>::<wbr><a href="../index.html">commands</a>::<wbr><a href="index.html">catalog</a></div><h1>Constant <span class="constant">VIDEO_<wbr>ITEM_<wbr>TYPES</span>&nbsp;<button id="copy-path" title="Copy item path to clipboard">Copy item path</button></h1><rustdoc-toolbar></rustdoc-toolbar><span class="sub-heading"><a class="src" href="../../../src/jellytau_lib/commands/catalog.rs.html#115">Source</a> </span></div><pre class="rust item-decl"><code>const VIDEO_ITEM_TYPES: &amp;[&amp;<a class="primitive" href="https://doc.rust-lang.org/1.97.1/std/primitive.str.html">str</a>];</code></pre><details class="toggle top-doc" open><summary class="hideme"><span>Expand description</span></summary><div class="docblock"><p>Jellyfin item types whose download is a <em>video</em> stream rather than an audio
one. The download queue stores an opaque <code>media_type</code> (audio/video); this
is where the taxonomy that produces it lives, so the frontend never has to
know which item types are video.</p>
<p>TRACES: UR-071 | DR-135</p>
</div></details></section></div></main></body></html>
@@ -0,0 +1,5 @@
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="Report the last-synced timestamp so the UI can show a hint / decide whether to trigger a fresh sync."><title>catalog_sync_status in jellytau_lib::commands::catalog - Rust</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-6b053e98.ttf.woff2,FiraSans-Italic-81dc35de.woff2,FiraSans-Regular-0fe48ade.woff2,FiraSans-MediumItalic-ccf7e434.woff2,FiraSans-Medium-e1aa3f0a.woff2,SourceCodePro-Regular-8badfe75.ttf.woff2,SourceCodePro-Semibold-aa29a496.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2"href="../../../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../../../static.files/normalize-9960930a.css"><link rel="stylesheet" href="../../../static.files/rustdoc-17e0aaed.css"><meta name="rustdoc-vars" data-root-path="../../../" data-static-root-path="../../../static.files/" data-current-crate="jellytau_lib" data-themes="" data-resource-suffix="" data-rustdoc-version="1.97.1 (8bab26f4f 2026-07-14)" data-channel="1.97.1" data-search-js="search-fd9372ac.js" data-stringdex-js="stringdex-2da4960a.js" data-settings-js="settings-170eb4bf.js" ><script src="../../../static.files/storage-41dd4d93.js"></script><script defer src="sidebar-items.js"></script><script defer src="../../../static.files/main-fcd733ba.js"></script><noscript><link rel="stylesheet" href="../../../static.files/noscript-f7c3ffd8.css"></noscript><link rel="alternate icon" type="image/png" href="../../../static.files/favicon-32x32-eab170b8.png"><link rel="icon" type="image/svg+xml" href="../../../static.files/favicon-044be391.svg"></head><body class="rustdoc fn"><a class="skip-main-content" href="#main-content">Skip to main content</a><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><rustdoc-topbar><h2><a href="#">catalog_sync_status</a></h2></rustdoc-topbar><nav class="sidebar"><div class="sidebar-crate"><h2><a href="../../../jellytau_lib/index.html">jellytau_<wbr>lib</a><span class="version">0.11.1</span></h2></div><div class="sidebar-elems"><div id="rustdoc-modnav"><h2><a href="index.html">In jellytau_<wbr>lib::<wbr>commands::<wbr>catalog</a></h2></div></div></nav><div class="sidebar-resizer" title="Drag to resize sidebar"></div><main><div class="width-limiter"><section id="main-content" class="content" tabindex="-1"><div class="main-heading"><div class="rustdoc-breadcrumbs"><a href="../../index.html">jellytau_lib</a>::<wbr><a href="../index.html">commands</a>::<wbr><a href="index.html">catalog</a></div><h1>Function <span class="fn">catalog_<wbr>sync_<wbr>status</span>&nbsp;<button id="copy-path" title="Copy item path to clipboard">Copy item path</button></h1><rustdoc-toolbar></rustdoc-toolbar><span class="sub-heading"><a class="src" href="../../../src/jellytau_lib/commands/catalog.rs.html#432-450">Source</a> </span></div><pre class="rust item-decl"><code>pub async fn catalog_sync_status(
db: State&lt;'_, <a class="struct" href="../storage/struct.DatabaseWrapper.html" title="struct jellytau_lib::commands::storage::DatabaseWrapper">DatabaseWrapper</a>&gt;,
) -&gt; <a class="enum" href="https://doc.rust-lang.org/1.97.1/core/result/enum.Result.html" title="enum core::result::Result">Result</a>&lt;<a class="struct" href="struct.CatalogSyncStatus.html" title="struct jellytau_lib::commands::catalog::CatalogSyncStatus">CatalogSyncStatus</a>, <a class="struct" href="https://doc.rust-lang.org/1.97.1/alloc/string/struct.String.html" title="struct alloc::string::String">String</a>&gt;</code></pre><details class="toggle top-doc" open><summary class="hideme"><span>Expand description</span></summary><div class="docblock"><p>Report the last-synced timestamp so the UI can show a hint / decide whether
to trigger a fresh sync.</p>
</div></details></section></div></main></body></html>
@@ -0,0 +1,10 @@
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="Whether an index pass is due, given when one last completed."><title>index_is_due in jellytau_lib::commands::catalog - Rust</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-6b053e98.ttf.woff2,FiraSans-Italic-81dc35de.woff2,FiraSans-Regular-0fe48ade.woff2,FiraSans-MediumItalic-ccf7e434.woff2,FiraSans-Medium-e1aa3f0a.woff2,SourceCodePro-Regular-8badfe75.ttf.woff2,SourceCodePro-Semibold-aa29a496.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2"href="../../../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../../../static.files/normalize-9960930a.css"><link rel="stylesheet" href="../../../static.files/rustdoc-17e0aaed.css"><meta name="rustdoc-vars" data-root-path="../../../" data-static-root-path="../../../static.files/" data-current-crate="jellytau_lib" data-themes="" data-resource-suffix="" data-rustdoc-version="1.97.1 (8bab26f4f 2026-07-14)" data-channel="1.97.1" data-search-js="search-fd9372ac.js" data-stringdex-js="stringdex-2da4960a.js" data-settings-js="settings-170eb4bf.js" ><script src="../../../static.files/storage-41dd4d93.js"></script><script defer src="sidebar-items.js"></script><script defer src="../../../static.files/main-fcd733ba.js"></script><noscript><link rel="stylesheet" href="../../../static.files/noscript-f7c3ffd8.css"></noscript><link rel="alternate icon" type="image/png" href="../../../static.files/favicon-32x32-eab170b8.png"><link rel="icon" type="image/svg+xml" href="../../../static.files/favicon-044be391.svg"></head><body class="rustdoc fn"><a class="skip-main-content" href="#main-content">Skip to main content</a><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><rustdoc-topbar><h2><a href="#">index_is_due</a></h2></rustdoc-topbar><nav class="sidebar"><div class="sidebar-crate"><h2><a href="../../../jellytau_lib/index.html">jellytau_<wbr>lib</a><span class="version">0.11.1</span></h2></div><div class="sidebar-elems"><div id="rustdoc-modnav"><h2><a href="index.html">In jellytau_<wbr>lib::<wbr>commands::<wbr>catalog</a></h2></div></div></nav><div class="sidebar-resizer" title="Drag to resize sidebar"></div><main><div class="width-limiter"><section id="main-content" class="content" tabindex="-1"><div class="main-heading"><div class="rustdoc-breadcrumbs"><a href="../../index.html">jellytau_lib</a>::<wbr><a href="../index.html">commands</a>::<wbr><a href="index.html">catalog</a></div><h1>Function <span class="fn">index_<wbr>is_<wbr>due</span>&nbsp;<button id="copy-path" title="Copy item path to clipboard">Copy item path</button></h1><rustdoc-toolbar></rustdoc-toolbar><span class="sub-heading"><a class="src" href="../../../src/jellytau_lib/commands/catalog.rs.html#282-299">Source</a> </span></div><pre class="rust item-decl"><code>pub(crate) fn index_is_due(
last_synced_at: <a class="enum" href="https://doc.rust-lang.org/1.97.1/core/option/enum.Option.html" title="enum core::option::Option">Option</a>&lt;&amp;<a class="primitive" href="https://doc.rust-lang.org/1.97.1/std/primitive.str.html">str</a>&gt;,
now: <a class="struct" href="https://docs.rs/chrono/latest/chrono/datetime/struct.DateTime.html" title="struct chrono::datetime::DateTime">DateTime</a>&lt;<a class="struct" href="https://docs.rs/chrono/latest/chrono/offset/utc/struct.Utc.html" title="struct chrono::offset::utc::Utc">Utc</a>&gt;,
ttl: <a class="struct" href="https://doc.rust-lang.org/1.97.1/core/time/struct.Duration.html" title="struct core::time::Duration">Duration</a>,
) -&gt; <a class="primitive" href="https://doc.rust-lang.org/1.97.1/std/primitive.bool.html">bool</a></code></pre><details class="toggle top-doc" open><summary class="hideme"><span>Expand description</span></summary><div class="docblock"><p>Whether an index pass is due, given when one last completed.</p>
<p>Pure so the policy is unit-testable without a clock, a server, or a database.
<code>None</code> (never indexed) and an unparseable stored value both mean “due” — a
corrupt timestamp should trigger a re-index, not silently freeze the catalog.</p>
<p>TRACES: UR-065 | DR-109 | UT-115</p>
</div></details></section></div></main></body></html>
@@ -0,0 +1,2 @@
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="One scheduler tick: check the preconditions, then index if due."><title>maybe_run_scheduled_pass in jellytau_lib::commands::catalog - Rust</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-6b053e98.ttf.woff2,FiraSans-Italic-81dc35de.woff2,FiraSans-Regular-0fe48ade.woff2,FiraSans-MediumItalic-ccf7e434.woff2,FiraSans-Medium-e1aa3f0a.woff2,SourceCodePro-Regular-8badfe75.ttf.woff2,SourceCodePro-Semibold-aa29a496.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2"href="../../../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../../../static.files/normalize-9960930a.css"><link rel="stylesheet" href="../../../static.files/rustdoc-17e0aaed.css"><meta name="rustdoc-vars" data-root-path="../../../" data-static-root-path="../../../static.files/" data-current-crate="jellytau_lib" data-themes="" data-resource-suffix="" data-rustdoc-version="1.97.1 (8bab26f4f 2026-07-14)" data-channel="1.97.1" data-search-js="search-fd9372ac.js" data-stringdex-js="stringdex-2da4960a.js" data-settings-js="settings-170eb4bf.js" ><script src="../../../static.files/storage-41dd4d93.js"></script><script defer src="sidebar-items.js"></script><script defer src="../../../static.files/main-fcd733ba.js"></script><noscript><link rel="stylesheet" href="../../../static.files/noscript-f7c3ffd8.css"></noscript><link rel="alternate icon" type="image/png" href="../../../static.files/favicon-32x32-eab170b8.png"><link rel="icon" type="image/svg+xml" href="../../../static.files/favicon-044be391.svg"></head><body class="rustdoc fn"><a class="skip-main-content" href="#main-content">Skip to main content</a><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><rustdoc-topbar><h2><a href="#">maybe_run_scheduled_pass</a></h2></rustdoc-topbar><nav class="sidebar"><div class="sidebar-crate"><h2><a href="../../../jellytau_lib/index.html">jellytau_<wbr>lib</a><span class="version">0.11.1</span></h2></div><div class="sidebar-elems"><div id="rustdoc-modnav"><h2><a href="index.html">In jellytau_<wbr>lib::<wbr>commands::<wbr>catalog</a></h2></div></div></nav><div class="sidebar-resizer" title="Drag to resize sidebar"></div><main><div class="width-limiter"><section id="main-content" class="content" tabindex="-1"><div class="main-heading"><div class="rustdoc-breadcrumbs"><a href="../../index.html">jellytau_lib</a>::<wbr><a href="../index.html">commands</a>::<wbr><a href="index.html">catalog</a></div><h1>Function <span class="fn">maybe_<wbr>run_<wbr>scheduled_<wbr>pass</span>&nbsp;<button id="copy-path" title="Copy item path to clipboard">Copy item path</button></h1><rustdoc-toolbar></rustdoc-toolbar><span class="sub-heading"><a class="src" href="../../../src/jellytau_lib/commands/catalog.rs.html#347-426">Source</a> </span></div><pre class="rust item-decl"><code>async fn maybe_run_scheduled_pass(app: &amp;AppHandle) -&gt; <a class="enum" href="https://doc.rust-lang.org/1.97.1/core/result/enum.Result.html" title="enum core::result::Result">Result</a>&lt;<a class="primitive" href="https://doc.rust-lang.org/1.97.1/std/primitive.unit.html">()</a>, <a class="struct" href="https://doc.rust-lang.org/1.97.1/alloc/string/struct.String.html" title="struct alloc::string::String">String</a>&gt;</code></pre><details class="toggle top-doc" open><summary class="hideme"><span>Expand description</span></summary><div class="docblock"><p>One scheduler tick: check the preconditions, then index if due.</p>
</div></details></section></div></main></body></html>
@@ -0,0 +1,2 @@
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="Read the last-sync timestamp straight from `app_settings`."><title>read_last_sync in jellytau_lib::commands::catalog - Rust</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-6b053e98.ttf.woff2,FiraSans-Italic-81dc35de.woff2,FiraSans-Regular-0fe48ade.woff2,FiraSans-MediumItalic-ccf7e434.woff2,FiraSans-Medium-e1aa3f0a.woff2,SourceCodePro-Regular-8badfe75.ttf.woff2,SourceCodePro-Semibold-aa29a496.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2"href="../../../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../../../static.files/normalize-9960930a.css"><link rel="stylesheet" href="../../../static.files/rustdoc-17e0aaed.css"><meta name="rustdoc-vars" data-root-path="../../../" data-static-root-path="../../../static.files/" data-current-crate="jellytau_lib" data-themes="" data-resource-suffix="" data-rustdoc-version="1.97.1 (8bab26f4f 2026-07-14)" data-channel="1.97.1" data-search-js="search-fd9372ac.js" data-stringdex-js="stringdex-2da4960a.js" data-settings-js="settings-170eb4bf.js" ><script src="../../../static.files/storage-41dd4d93.js"></script><script defer src="sidebar-items.js"></script><script defer src="../../../static.files/main-fcd733ba.js"></script><noscript><link rel="stylesheet" href="../../../static.files/noscript-f7c3ffd8.css"></noscript><link rel="alternate icon" type="image/png" href="../../../static.files/favicon-32x32-eab170b8.png"><link rel="icon" type="image/svg+xml" href="../../../static.files/favicon-044be391.svg"></head><body class="rustdoc fn"><a class="skip-main-content" href="#main-content">Skip to main content</a><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><rustdoc-topbar><h2><a href="#">read_last_sync</a></h2></rustdoc-topbar><nav class="sidebar"><div class="sidebar-crate"><h2><a href="../../../jellytau_lib/index.html">jellytau_<wbr>lib</a><span class="version">0.11.1</span></h2></div><div class="sidebar-elems"><div id="rustdoc-modnav"><h2><a href="index.html">In jellytau_<wbr>lib::<wbr>commands::<wbr>catalog</a></h2></div></div></nav><div class="sidebar-resizer" title="Drag to resize sidebar"></div><main><div class="width-limiter"><section id="main-content" class="content" tabindex="-1"><div class="main-heading"><div class="rustdoc-breadcrumbs"><a href="../../index.html">jellytau_lib</a>::<wbr><a href="../index.html">commands</a>::<wbr><a href="index.html">catalog</a></div><h1>Function <span class="fn">read_<wbr>last_<wbr>sync</span>&nbsp;<button id="copy-path" title="Copy item path to clipboard">Copy item path</button></h1><rustdoc-toolbar></rustdoc-toolbar><span class="sub-heading"><a class="src" href="../../../src/jellytau_lib/commands/catalog.rs.html#302-316">Source</a> </span></div><pre class="rust item-decl"><code>async fn read_last_sync(db_service: &amp;<a class="struct" href="https://doc.rust-lang.org/1.97.1/alloc/sync/struct.Arc.html" title="struct alloc::sync::Arc">Arc</a>&lt;<a class="struct" href="../../storage/db_service/struct.RusqliteService.html" title="struct jellytau_lib::storage::db_service::RusqliteService">RusqliteService</a>&gt;) -&gt; <a class="enum" href="https://doc.rust-lang.org/1.97.1/core/option/enum.Option.html" title="enum core::option::Option">Option</a>&lt;<a class="struct" href="https://doc.rust-lang.org/1.97.1/alloc/string/struct.String.html" title="struct alloc::string::String">String</a>&gt;</code></pre><details class="toggle top-doc" open><summary class="hideme"><span>Expand description</span></summary><div class="docblock"><p>Read the last-sync timestamp straight from <code>app_settings</code>.</p>
</div></details></section></div></main></body></html>
@@ -0,0 +1,15 @@
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="Requeue video downloads that were fetched as audio."><title>requeue_mistyped_video_downloads in jellytau_lib::commands::catalog - Rust</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-6b053e98.ttf.woff2,FiraSans-Italic-81dc35de.woff2,FiraSans-Regular-0fe48ade.woff2,FiraSans-MediumItalic-ccf7e434.woff2,FiraSans-Medium-e1aa3f0a.woff2,SourceCodePro-Regular-8badfe75.ttf.woff2,SourceCodePro-Semibold-aa29a496.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2"href="../../../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../../../static.files/normalize-9960930a.css"><link rel="stylesheet" href="../../../static.files/rustdoc-17e0aaed.css"><meta name="rustdoc-vars" data-root-path="../../../" data-static-root-path="../../../static.files/" data-current-crate="jellytau_lib" data-themes="" data-resource-suffix="" data-rustdoc-version="1.97.1 (8bab26f4f 2026-07-14)" data-channel="1.97.1" data-search-js="search-fd9372ac.js" data-stringdex-js="stringdex-2da4960a.js" data-settings-js="settings-170eb4bf.js" ><script src="../../../static.files/storage-41dd4d93.js"></script><script defer src="sidebar-items.js"></script><script defer src="../../../static.files/main-fcd733ba.js"></script><noscript><link rel="stylesheet" href="../../../static.files/noscript-f7c3ffd8.css"></noscript><link rel="alternate icon" type="image/png" href="../../../static.files/favicon-32x32-eab170b8.png"><link rel="icon" type="image/svg+xml" href="../../../static.files/favicon-044be391.svg"></head><body class="rustdoc fn"><a class="skip-main-content" href="#main-content">Skip to main content</a><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><rustdoc-topbar><h2><a href="#">requeue_mistyped_video_downloads</a></h2></rustdoc-topbar><nav class="sidebar"><div class="sidebar-crate"><h2><a href="../../../jellytau_lib/index.html">jellytau_<wbr>lib</a><span class="version">0.11.1</span></h2></div><div class="sidebar-elems"><div id="rustdoc-modnav"><h2><a href="index.html">In jellytau_<wbr>lib::<wbr>commands::<wbr>catalog</a></h2></div></div></nav><div class="sidebar-resizer" title="Drag to resize sidebar"></div><main><div class="width-limiter"><section id="main-content" class="content" tabindex="-1"><div class="main-heading"><div class="rustdoc-breadcrumbs"><a href="../../index.html">jellytau_lib</a>::<wbr><a href="../index.html">commands</a>::<wbr><a href="index.html">catalog</a></div><h1>Function <span class="fn">requeue_<wbr>mistyped_<wbr>video_<wbr>downloads</span>&nbsp;<button id="copy-path" title="Copy item path to clipboard">Copy item path</button></h1><rustdoc-toolbar></rustdoc-toolbar><span class="sub-heading"><a class="src" href="../../../src/jellytau_lib/commands/catalog.rs.html#491-518">Source</a> </span></div><pre class="rust item-decl"><code>pub(crate) async fn requeue_mistyped_video_downloads(
db_service: &amp;<a class="struct" href="https://doc.rust-lang.org/1.97.1/alloc/sync/struct.Arc.html" title="struct alloc::sync::Arc">Arc</a>&lt;<a class="struct" href="../../storage/db_service/struct.RusqliteService.html" title="struct jellytau_lib::storage::db_service::RusqliteService">RusqliteService</a>&gt;,
) -&gt; <a class="enum" href="https://doc.rust-lang.org/1.97.1/core/result/enum.Result.html" title="enum core::result::Result">Result</a>&lt;<a class="primitive" href="https://doc.rust-lang.org/1.97.1/std/primitive.usize.html">usize</a>, <a class="struct" href="https://doc.rust-lang.org/1.97.1/alloc/string/struct.String.html" title="struct alloc::string::String">String</a>&gt;</code></pre><details class="toggle top-doc" open><summary class="hideme"><span>Expand description</span></summary><div class="docblock"><p>Requeue video downloads that were fetched as audio.</p>
<p>Before <a href="fn.resolve_pending_download_urls.html" title="fn jellytau_lib::commands::catalog::resolve_pending_download_urls"><code>resolve_pending_download_urls</code></a> consulted the items type, a row
with no <code>media_type</code> — which is every row queued from a media card, since
<code>download_item</code> does not record one — resolved against
<code>get_audio_stream_url</code>. A movie queued that way completed with an audio-only
transcode on disk, so playing it offline could only ever fail. Those rows are
identifiable after the fact (no <code>media_type</code>, but a video item), so reset them
to pending with no URL and let the resolver fetch the real video.</p>
<p>Rows carrying an explicit <code>media_type</code> were resolved correctly and are left
alone, as are genuine audio downloads.</p>
<p>Returns the number of rows requeued.</p>
<p>TRACES: UR-071 | DR-136 | UT-126</p>
</div></details></section></div></main></body></html>
@@ -0,0 +1,16 @@
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="Core of `resume_queued_downloads`, factored out for testing: select every `pending`/`stream_url IS NULL` row, resolve each via `resolve` (returning `None` leaves the row pending), and heal the row so the pump can start it. The `resolve` closure receives `(item_id, media_type, quality_preset)`."><title>resolve_pending_download_urls in jellytau_lib::commands::catalog - Rust</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-6b053e98.ttf.woff2,FiraSans-Italic-81dc35de.woff2,FiraSans-Regular-0fe48ade.woff2,FiraSans-MediumItalic-ccf7e434.woff2,FiraSans-Medium-e1aa3f0a.woff2,SourceCodePro-Regular-8badfe75.ttf.woff2,SourceCodePro-Semibold-aa29a496.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2"href="../../../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../../../static.files/normalize-9960930a.css"><link rel="stylesheet" href="../../../static.files/rustdoc-17e0aaed.css"><meta name="rustdoc-vars" data-root-path="../../../" data-static-root-path="../../../static.files/" data-current-crate="jellytau_lib" data-themes="" data-resource-suffix="" data-rustdoc-version="1.97.1 (8bab26f4f 2026-07-14)" data-channel="1.97.1" data-search-js="search-fd9372ac.js" data-stringdex-js="stringdex-2da4960a.js" data-settings-js="settings-170eb4bf.js" ><script src="../../../static.files/storage-41dd4d93.js"></script><script defer src="sidebar-items.js"></script><script defer src="../../../static.files/main-fcd733ba.js"></script><noscript><link rel="stylesheet" href="../../../static.files/noscript-f7c3ffd8.css"></noscript><link rel="alternate icon" type="image/png" href="../../../static.files/favicon-32x32-eab170b8.png"><link rel="icon" type="image/svg+xml" href="../../../static.files/favicon-044be391.svg"></head><body class="rustdoc fn"><a class="skip-main-content" href="#main-content">Skip to main content</a><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><rustdoc-topbar><h2><a href="#">resolve_pending_download_urls</a></h2></rustdoc-topbar><nav class="sidebar"><div class="sidebar-crate"><h2><a href="../../../jellytau_lib/index.html">jellytau_<wbr>lib</a><span class="version">0.11.1</span></h2></div><div class="sidebar-elems"><div id="rustdoc-modnav"><h2><a href="index.html">In jellytau_<wbr>lib::<wbr>commands::<wbr>catalog</a></h2></div></div></nav><div class="sidebar-resizer" title="Drag to resize sidebar"></div><main><div class="width-limiter"><section id="main-content" class="content" tabindex="-1"><div class="main-heading"><div class="rustdoc-breadcrumbs"><a href="../../index.html">jellytau_lib</a>::<wbr><a href="../index.html">commands</a>::<wbr><a href="index.html">catalog</a></div><h1>Function <span class="fn">resolve_<wbr>pending_<wbr>download_<wbr>urls</span>&nbsp;<button id="copy-path" title="Copy item path to clipboard">Copy item path</button></h1><rustdoc-toolbar></rustdoc-toolbar><span class="sub-heading"><a class="src" href="../../../src/jellytau_lib/commands/catalog.rs.html#529-636">Source</a> </span></div><pre class="rust item-decl"><code>pub(crate) async fn resolve_pending_download_urls&lt;F, Fut&gt;(
db_service: &amp;<a class="struct" href="https://doc.rust-lang.org/1.97.1/alloc/sync/struct.Arc.html" title="struct alloc::sync::Arc">Arc</a>&lt;<a class="struct" href="../../storage/db_service/struct.RusqliteService.html" title="struct jellytau_lib::storage::db_service::RusqliteService">RusqliteService</a>&gt;,
target_dir: &amp;<a class="primitive" href="https://doc.rust-lang.org/1.97.1/std/primitive.str.html">str</a>,
only_ids: <a class="enum" href="https://doc.rust-lang.org/1.97.1/core/option/enum.Option.html" title="enum core::option::Option">Option</a>&lt;&amp;[<a class="primitive" href="https://doc.rust-lang.org/1.97.1/std/primitive.i64.html">i64</a>]&gt;,
resolve: F,
) -&gt; <a class="enum" href="https://doc.rust-lang.org/1.97.1/core/result/enum.Result.html" title="enum core::result::Result">Result</a>&lt;<a class="struct" href="struct.ResumeQueuedResult.html" title="struct jellytau_lib::commands::catalog::ResumeQueuedResult">ResumeQueuedResult</a>, <a class="struct" href="https://doc.rust-lang.org/1.97.1/alloc/string/struct.String.html" title="struct alloc::string::String">String</a>&gt;<div class="where">where
F: <a class="trait" href="https://doc.rust-lang.org/1.97.1/core/ops/function/trait.Fn.html" title="trait core::ops::function::Fn">Fn</a>(<a class="struct" href="https://doc.rust-lang.org/1.97.1/alloc/string/struct.String.html" title="struct alloc::string::String">String</a>, <a class="struct" href="https://doc.rust-lang.org/1.97.1/alloc/string/struct.String.html" title="struct alloc::string::String">String</a>, <a class="struct" href="https://doc.rust-lang.org/1.97.1/alloc/string/struct.String.html" title="struct alloc::string::String">String</a>) -&gt; Fut,
Fut: <a class="trait" href="https://doc.rust-lang.org/1.97.1/core/future/future/trait.Future.html" title="trait core::future::future::Future">Future</a>&lt;Output = <a class="enum" href="https://doc.rust-lang.org/1.97.1/core/option/enum.Option.html" title="enum core::option::Option">Option</a>&lt;<a class="struct" href="https://doc.rust-lang.org/1.97.1/alloc/string/struct.String.html" title="struct alloc::string::String">String</a>&gt;&gt;,</div></code></pre><details class="toggle top-doc" open><summary class="hideme"><span>Expand description</span></summary><div class="docblock"><p>Core of <a href="fn.resume_queued_downloads.html" title="fn jellytau_lib::commands::catalog::resume_queued_downloads"><code>resume_queued_downloads</code></a>, factored out for testing: select every
<code>pending</code>/<code>stream_url IS NULL</code> row, resolve each via <code>resolve</code> (returning
<code>None</code> leaves the row pending), and heal the row so the pump can start it.
The <code>resolve</code> closure receives <code>(item_id, media_type, quality_preset)</code>.</p>
<p><code>only_ids</code> restricts the sweep to specific download rows. Reconnect passes
<code>None</code> and heals everything; a bulk enqueue (an album, say) passes the rows
it just created, so clicking download on one album cannot also start every
unrelated row that has been sitting pending.</p>
</div></details></section></div></main></body></html>
@@ -0,0 +1,14 @@
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="Resolve the stream URL for every download row that was queued while offline (`status = &#39;pending&#39; AND stream_url IS NULL`), then pump the queue so they start. Call this on reconnect."><title>resume_queued_downloads in jellytau_lib::commands::catalog - Rust</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-6b053e98.ttf.woff2,FiraSans-Italic-81dc35de.woff2,FiraSans-Regular-0fe48ade.woff2,FiraSans-MediumItalic-ccf7e434.woff2,FiraSans-Medium-e1aa3f0a.woff2,SourceCodePro-Regular-8badfe75.ttf.woff2,SourceCodePro-Semibold-aa29a496.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2"href="../../../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../../../static.files/normalize-9960930a.css"><link rel="stylesheet" href="../../../static.files/rustdoc-17e0aaed.css"><meta name="rustdoc-vars" data-root-path="../../../" data-static-root-path="../../../static.files/" data-current-crate="jellytau_lib" data-themes="" data-resource-suffix="" data-rustdoc-version="1.97.1 (8bab26f4f 2026-07-14)" data-channel="1.97.1" data-search-js="search-fd9372ac.js" data-stringdex-js="stringdex-2da4960a.js" data-settings-js="settings-170eb4bf.js" ><script src="../../../static.files/storage-41dd4d93.js"></script><script defer src="sidebar-items.js"></script><script defer src="../../../static.files/main-fcd733ba.js"></script><noscript><link rel="stylesheet" href="../../../static.files/noscript-f7c3ffd8.css"></noscript><link rel="alternate icon" type="image/png" href="../../../static.files/favicon-32x32-eab170b8.png"><link rel="icon" type="image/svg+xml" href="../../../static.files/favicon-044be391.svg"></head><body class="rustdoc fn"><a class="skip-main-content" href="#main-content">Skip to main content</a><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><rustdoc-topbar><h2><a href="#">resume_queued_downloads</a></h2></rustdoc-topbar><nav class="sidebar"><div class="sidebar-crate"><h2><a href="../../../jellytau_lib/index.html">jellytau_<wbr>lib</a><span class="version">0.11.1</span></h2></div><div class="sidebar-elems"><div id="rustdoc-modnav"><h2><a href="index.html">In jellytau_<wbr>lib::<wbr>commands::<wbr>catalog</a></h2></div></div></nav><div class="sidebar-resizer" title="Drag to resize sidebar"></div><main><div class="width-limiter"><section id="main-content" class="content" tabindex="-1"><div class="main-heading"><div class="rustdoc-breadcrumbs"><a href="../../index.html">jellytau_lib</a>::<wbr><a href="../index.html">commands</a>::<wbr><a href="index.html">catalog</a></div><h1>Function <span class="fn">resume_<wbr>queued_<wbr>downloads</span>&nbsp;<button id="copy-path" title="Copy item path to clipboard">Copy item path</button></h1><rustdoc-toolbar></rustdoc-toolbar><span class="sub-heading"><a class="src" href="../../../src/jellytau_lib/commands/catalog.rs.html#648-751">Source</a> </span></div><pre class="rust item-decl"><code>pub async fn resume_queued_downloads(
repository: State&lt;'_, <a class="struct" href="../repository/struct.RepositoryManagerWrapper.html" title="struct jellytau_lib::commands::repository::RepositoryManagerWrapper">RepositoryManagerWrapper</a>&gt;,
db: State&lt;'_, <a class="struct" href="../storage/struct.DatabaseWrapper.html" title="struct jellytau_lib::commands::storage::DatabaseWrapper">DatabaseWrapper</a>&gt;,
download_manager: State&lt;'_, <a class="struct" href="../download/struct.DownloadManagerWrapper.html" title="struct jellytau_lib::commands::download::DownloadManagerWrapper">DownloadManagerWrapper</a>&gt;,
app: AppHandle,
handle: <a class="struct" href="https://doc.rust-lang.org/1.97.1/alloc/string/struct.String.html" title="struct alloc::string::String">String</a>,
) -&gt; <a class="enum" href="https://doc.rust-lang.org/1.97.1/core/result/enum.Result.html" title="enum core::result::Result">Result</a>&lt;<a class="struct" href="struct.ResumeQueuedResult.html" title="struct jellytau_lib::commands::catalog::ResumeQueuedResult">ResumeQueuedResult</a>, <a class="struct" href="https://doc.rust-lang.org/1.97.1/alloc/string/struct.String.html" title="struct alloc::string::String">String</a>&gt;</code></pre><details class="toggle top-doc" open><summary class="hideme"><span>Expand description</span></summary><div class="docblock"><p>Resolve the stream URL for every download row that was queued while offline
(<code>status = 'pending' AND stream_url IS NULL</code>), then pump the queue so they
start. Call this on reconnect.</p>
<p>Audio rows resolve via <code>get_audio_stream_url</code>; video rows (media_type =
video) via the pure <code>get_video_download_url</code> builder using the rows stored
<code>quality_preset</code> — mirroring <code>enqueue_video_downloads</code>. Rows whose URL cant
be resolved are left pending (they retry on the next reconnect).</p>
</div></details></section></div></main></body></html>
@@ -0,0 +1,8 @@
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="One full-catalog indexing pass, shared by the `sync_full_catalog` command and the background scheduler (DR-109) so there is exactly one implementation and one concurrency guard."><title>run_index_pass in jellytau_lib::commands::catalog - Rust</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-6b053e98.ttf.woff2,FiraSans-Italic-81dc35de.woff2,FiraSans-Regular-0fe48ade.woff2,FiraSans-MediumItalic-ccf7e434.woff2,FiraSans-Medium-e1aa3f0a.woff2,SourceCodePro-Regular-8badfe75.ttf.woff2,SourceCodePro-Semibold-aa29a496.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2"href="../../../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../../../static.files/normalize-9960930a.css"><link rel="stylesheet" href="../../../static.files/rustdoc-17e0aaed.css"><meta name="rustdoc-vars" data-root-path="../../../" data-static-root-path="../../../static.files/" data-current-crate="jellytau_lib" data-themes="" data-resource-suffix="" data-rustdoc-version="1.97.1 (8bab26f4f 2026-07-14)" data-channel="1.97.1" data-search-js="search-fd9372ac.js" data-stringdex-js="stringdex-2da4960a.js" data-settings-js="settings-170eb4bf.js" ><script src="../../../static.files/storage-41dd4d93.js"></script><script defer src="sidebar-items.js"></script><script defer src="../../../static.files/main-fcd733ba.js"></script><noscript><link rel="stylesheet" href="../../../static.files/noscript-f7c3ffd8.css"></noscript><link rel="alternate icon" type="image/png" href="../../../static.files/favicon-32x32-eab170b8.png"><link rel="icon" type="image/svg+xml" href="../../../static.files/favicon-044be391.svg"></head><body class="rustdoc fn"><a class="skip-main-content" href="#main-content">Skip to main content</a><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><rustdoc-topbar><h2><a href="#">run_index_pass</a></h2></rustdoc-topbar><nav class="sidebar"><div class="sidebar-crate"><h2><a href="../../../jellytau_lib/index.html">jellytau_<wbr>lib</a><span class="version">0.11.1</span></h2></div><div class="sidebar-elems"><div id="rustdoc-modnav"><h2><a href="index.html">In jellytau_<wbr>lib::<wbr>commands::<wbr>catalog</a></h2></div></div></nav><div class="sidebar-resizer" title="Drag to resize sidebar"></div><main><div class="width-limiter"><section id="main-content" class="content" tabindex="-1"><div class="main-heading"><div class="rustdoc-breadcrumbs"><a href="../../index.html">jellytau_lib</a>::<wbr><a href="../index.html">commands</a>::<wbr><a href="index.html">catalog</a></div><h1>Function <span class="fn">run_<wbr>index_<wbr>pass</span>&nbsp;<button id="copy-path" title="Copy item path to clipboard">Copy item path</button></h1><rustdoc-toolbar></rustdoc-toolbar><span class="sub-heading"><a class="src" href="../../../src/jellytau_lib/commands/catalog.rs.html#165-273">Source</a> </span></div><pre class="rust item-decl"><code>pub(crate) async fn run_index_pass(
repo: <a class="struct" href="https://doc.rust-lang.org/1.97.1/alloc/sync/struct.Arc.html" title="struct alloc::sync::Arc">Arc</a>&lt;<a class="struct" href="../../repository/hybrid/struct.HybridRepository.html" title="struct jellytau_lib::repository::hybrid::HybridRepository">HybridRepository</a>&gt;,
db_service: <a class="struct" href="https://doc.rust-lang.org/1.97.1/alloc/sync/struct.Arc.html" title="struct alloc::sync::Arc">Arc</a>&lt;<a class="struct" href="../../storage/db_service/struct.RusqliteService.html" title="struct jellytau_lib::storage::db_service::RusqliteService">RusqliteService</a>&gt;,
) -&gt; <a class="enum" href="https://doc.rust-lang.org/1.97.1/core/result/enum.Result.html" title="enum core::result::Result">Result</a>&lt;<a class="struct" href="struct.CatalogSyncResult.html" title="struct jellytau_lib::commands::catalog::CatalogSyncResult">CatalogSyncResult</a>, <a class="struct" href="https://doc.rust-lang.org/1.97.1/alloc/string/struct.String.html" title="struct alloc::string::String">String</a>&gt;</code></pre><details class="toggle top-doc" open><summary class="hideme"><span>Expand description</span></summary><div class="docblock"><p>One full-catalog indexing pass, shared by the <a href="fn.sync_full_catalog.html" title="fn jellytau_lib::commands::catalog::sync_full_catalog"><code>sync_full_catalog</code></a> command
and the background scheduler (DR-109) so there is exactly one implementation
and one concurrency guard.</p>
<p>TRACES: UR-065 | DR-109, DR-110</p>
</div></details></section></div></main></body></html>
@@ -0,0 +1,8 @@
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="Control whether offline library queries reveal the full synced catalog (greyed-out, non-downloaded media) or only downloaded/local media."><title>set_show_server_catalog in jellytau_lib::commands::catalog - Rust</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-6b053e98.ttf.woff2,FiraSans-Italic-81dc35de.woff2,FiraSans-Regular-0fe48ade.woff2,FiraSans-MediumItalic-ccf7e434.woff2,FiraSans-Medium-e1aa3f0a.woff2,SourceCodePro-Regular-8badfe75.ttf.woff2,SourceCodePro-Semibold-aa29a496.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2"href="../../../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../../../static.files/normalize-9960930a.css"><link rel="stylesheet" href="../../../static.files/rustdoc-17e0aaed.css"><meta name="rustdoc-vars" data-root-path="../../../" data-static-root-path="../../../static.files/" data-current-crate="jellytau_lib" data-themes="" data-resource-suffix="" data-rustdoc-version="1.97.1 (8bab26f4f 2026-07-14)" data-channel="1.97.1" data-search-js="search-fd9372ac.js" data-stringdex-js="stringdex-2da4960a.js" data-settings-js="settings-170eb4bf.js" ><script src="../../../static.files/storage-41dd4d93.js"></script><script defer src="sidebar-items.js"></script><script defer src="../../../static.files/main-fcd733ba.js"></script><noscript><link rel="stylesheet" href="../../../static.files/noscript-f7c3ffd8.css"></noscript><link rel="alternate icon" type="image/png" href="../../../static.files/favicon-32x32-eab170b8.png"><link rel="icon" type="image/svg+xml" href="../../../static.files/favicon-044be391.svg"></head><body class="rustdoc fn"><a class="skip-main-content" href="#main-content">Skip to main content</a><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><rustdoc-topbar><h2><a href="#">set_show_server_catalog</a></h2></rustdoc-topbar><nav class="sidebar"><div class="sidebar-crate"><h2><a href="../../../jellytau_lib/index.html">jellytau_<wbr>lib</a><span class="version">0.11.1</span></h2></div><div class="sidebar-elems"><div id="rustdoc-modnav"><h2><a href="index.html">In jellytau_<wbr>lib::<wbr>commands::<wbr>catalog</a></h2></div></div></nav><div class="sidebar-resizer" title="Drag to resize sidebar"></div><main><div class="width-limiter"><section id="main-content" class="content" tabindex="-1"><div class="main-heading"><div class="rustdoc-breadcrumbs"><a href="../../index.html">jellytau_lib</a>::<wbr><a href="../index.html">commands</a>::<wbr><a href="index.html">catalog</a></div><h1>Function <span class="fn">set_<wbr>show_<wbr>server_<wbr>catalog</span>&nbsp;<button id="copy-path" title="Copy item path to clipboard">Copy item path</button></h1><rustdoc-toolbar></rustdoc-toolbar><span class="sub-heading"><a class="src" href="../../../src/jellytau_lib/commands/catalog.rs.html#462-464">Source</a> </span></div><pre class="rust item-decl"><code>pub fn set_show_server_catalog(show: <a class="primitive" href="https://doc.rust-lang.org/1.97.1/std/primitive.bool.html">bool</a>)</code></pre><details class="toggle top-doc" open><summary class="hideme"><span>Expand description</span></summary><div class="docblock"><p>Control whether offline library queries reveal the full synced catalog
(greyed-out, non-downloaded media) or only downloaded/local media.</p>
<p>The frontend calls this from the “Show all server media” toggle: pass <code>true</code>
when online, or when offline with the toggle on; pass <code>false</code> when offline
with the toggle off so library pages show downloaded media only. Fixes the
bug where offline library pages showed every server item regardless of the
toggle.</p>
</div></details></section></div></main></body></html>
@@ -0,0 +1,9 @@
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="Start the background catalog indexer."><title>spawn_catalog_indexer in jellytau_lib::commands::catalog - Rust</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-6b053e98.ttf.woff2,FiraSans-Italic-81dc35de.woff2,FiraSans-Regular-0fe48ade.woff2,FiraSans-MediumItalic-ccf7e434.woff2,FiraSans-Medium-e1aa3f0a.woff2,SourceCodePro-Regular-8badfe75.ttf.woff2,SourceCodePro-Semibold-aa29a496.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2"href="../../../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../../../static.files/normalize-9960930a.css"><link rel="stylesheet" href="../../../static.files/rustdoc-17e0aaed.css"><meta name="rustdoc-vars" data-root-path="../../../" data-static-root-path="../../../static.files/" data-current-crate="jellytau_lib" data-themes="" data-resource-suffix="" data-rustdoc-version="1.97.1 (8bab26f4f 2026-07-14)" data-channel="1.97.1" data-search-js="search-fd9372ac.js" data-stringdex-js="stringdex-2da4960a.js" data-settings-js="settings-170eb4bf.js" ><script src="../../../static.files/storage-41dd4d93.js"></script><script defer src="sidebar-items.js"></script><script defer src="../../../static.files/main-fcd733ba.js"></script><noscript><link rel="stylesheet" href="../../../static.files/noscript-f7c3ffd8.css"></noscript><link rel="alternate icon" type="image/png" href="../../../static.files/favicon-32x32-eab170b8.png"><link rel="icon" type="image/svg+xml" href="../../../static.files/favicon-044be391.svg"></head><body class="rustdoc fn"><a class="skip-main-content" href="#main-content">Skip to main content</a><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><rustdoc-topbar><h2><a href="#">spawn_catalog_indexer</a></h2></rustdoc-topbar><nav class="sidebar"><div class="sidebar-crate"><h2><a href="../../../jellytau_lib/index.html">jellytau_<wbr>lib</a><span class="version">0.11.1</span></h2></div><div class="sidebar-elems"><div id="rustdoc-modnav"><h2><a href="index.html">In jellytau_<wbr>lib::<wbr>commands::<wbr>catalog</a></h2></div></div></nav><div class="sidebar-resizer" title="Drag to resize sidebar"></div><main><div class="width-limiter"><section id="main-content" class="content" tabindex="-1"><div class="main-heading"><div class="rustdoc-breadcrumbs"><a href="../../index.html">jellytau_lib</a>::<wbr><a href="../index.html">commands</a>::<wbr><a href="index.html">catalog</a></div><h1>Function <span class="fn">spawn_<wbr>catalog_<wbr>indexer</span>&nbsp;<button id="copy-path" title="Copy item path to clipboard">Copy item path</button></h1><rustdoc-toolbar></rustdoc-toolbar><span class="sub-heading"><a class="src" href="../../../src/jellytau_lib/commands/catalog.rs.html#328-344">Source</a> </span></div><pre class="rust item-decl"><code>pub fn spawn_catalog_indexer(app: AppHandle)</code></pre><details class="toggle top-doc" open><summary class="hideme"><span>Expand description</span></summary><div class="docblock"><p>Start the background catalog indexer.</p>
<p>Replaces the frontends startup-only <code>syncCatalog()</code> call: index freshness is
sync policy and belongs in Rust (see the layer assignment in
docs/architecture/03-data-flow.md, “Search Flow”). Ticks every
<a href="constant.CATALOG_INDEX_TICK.html" title="constant jellytau_lib::commands::catalog::CATALOG_INDEX_TICK"><code>CATALOG_INDEX_TICK</code></a> and
runs a pass when a repository exists, the server is reachable, and the index
is older than <a href="constant.CATALOG_INDEX_TTL.html" title="constant jellytau_lib::commands::catalog::CATALOG_INDEX_TTL"><code>CATALOG_INDEX_TTL</code></a>.</p>
<p>TRACES: UR-065 | DR-109, IR-030</p>
</div></details></section></div></main></body></html>
@@ -0,0 +1,11 @@
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="Walk every library on the server and persist all items to the offline cache so the full catalog is browsable offline (greyed out when not downloaded)."><title>sync_full_catalog in jellytau_lib::commands::catalog - Rust</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-6b053e98.ttf.woff2,FiraSans-Italic-81dc35de.woff2,FiraSans-Regular-0fe48ade.woff2,FiraSans-MediumItalic-ccf7e434.woff2,FiraSans-Medium-e1aa3f0a.woff2,SourceCodePro-Regular-8badfe75.ttf.woff2,SourceCodePro-Semibold-aa29a496.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2"href="../../../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../../../static.files/normalize-9960930a.css"><link rel="stylesheet" href="../../../static.files/rustdoc-17e0aaed.css"><meta name="rustdoc-vars" data-root-path="../../../" data-static-root-path="../../../static.files/" data-current-crate="jellytau_lib" data-themes="" data-resource-suffix="" data-rustdoc-version="1.97.1 (8bab26f4f 2026-07-14)" data-channel="1.97.1" data-search-js="search-fd9372ac.js" data-stringdex-js="stringdex-2da4960a.js" data-settings-js="settings-170eb4bf.js" ><script src="../../../static.files/storage-41dd4d93.js"></script><script defer src="sidebar-items.js"></script><script defer src="../../../static.files/main-fcd733ba.js"></script><noscript><link rel="stylesheet" href="../../../static.files/noscript-f7c3ffd8.css"></noscript><link rel="alternate icon" type="image/png" href="../../../static.files/favicon-32x32-eab170b8.png"><link rel="icon" type="image/svg+xml" href="../../../static.files/favicon-044be391.svg"></head><body class="rustdoc fn"><a class="skip-main-content" href="#main-content">Skip to main content</a><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><rustdoc-topbar><h2><a href="#">sync_full_catalog</a></h2></rustdoc-topbar><nav class="sidebar"><div class="sidebar-crate"><h2><a href="../../../jellytau_lib/index.html">jellytau_<wbr>lib</a><span class="version">0.11.1</span></h2></div><div class="sidebar-elems"><div id="rustdoc-modnav"><h2><a href="index.html">In jellytau_<wbr>lib::<wbr>commands::<wbr>catalog</a></h2></div></div></nav><div class="sidebar-resizer" title="Drag to resize sidebar"></div><main><div class="width-limiter"><section id="main-content" class="content" tabindex="-1"><div class="main-heading"><div class="rustdoc-breadcrumbs"><a href="../../index.html">jellytau_lib</a>::<wbr><a href="../index.html">commands</a>::<wbr><a href="index.html">catalog</a></div><h1>Function <span class="fn">sync_<wbr>full_<wbr>catalog</span>&nbsp;<button id="copy-path" title="Copy item path to clipboard">Copy item path</button></h1><rustdoc-toolbar></rustdoc-toolbar><span class="sub-heading"><a class="src" href="../../../src/jellytau_lib/commands/catalog.rs.html#145-158">Source</a> </span></div><pre class="rust item-decl"><code>pub async fn sync_full_catalog(
repository: State&lt;'_, <a class="struct" href="../repository/struct.RepositoryManagerWrapper.html" title="struct jellytau_lib::commands::repository::RepositoryManagerWrapper">RepositoryManagerWrapper</a>&gt;,
db: State&lt;'_, <a class="struct" href="../storage/struct.DatabaseWrapper.html" title="struct jellytau_lib::commands::storage::DatabaseWrapper">DatabaseWrapper</a>&gt;,
handle: <a class="struct" href="https://doc.rust-lang.org/1.97.1/alloc/string/struct.String.html" title="struct alloc::string::String">String</a>,
) -&gt; <a class="enum" href="https://doc.rust-lang.org/1.97.1/core/result/enum.Result.html" title="enum core::result::Result">Result</a>&lt;<a class="struct" href="struct.CatalogSyncResult.html" title="struct jellytau_lib::commands::catalog::CatalogSyncResult">CatalogSyncResult</a>, <a class="struct" href="https://doc.rust-lang.org/1.97.1/alloc/string/struct.String.html" title="struct alloc::string::String">String</a>&gt;</code></pre><details class="toggle top-doc" open><summary class="hideme"><span>Expand description</span></summary><div class="docblock"><p>Walk every library on the server and persist all items to the offline cache
so the full catalog is browsable offline (greyed out when not downloaded).</p>
<p>Best-effort: a library that fails to fetch is counted and skipped rather than
aborting the whole sync. Runs libraries sequentially to avoid hammering the
server. Uses <code>Recursive=true</code> so a single request per library returns the
containers and their playable children.</p>
</div></details></section></div></main></body></html>
@@ -0,0 +1,46 @@
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="Tauri commands for the offline “browse &#38; queue” feature."><title>jellytau_lib::commands::catalog - Rust</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-6b053e98.ttf.woff2,FiraSans-Italic-81dc35de.woff2,FiraSans-Regular-0fe48ade.woff2,FiraSans-MediumItalic-ccf7e434.woff2,FiraSans-Medium-e1aa3f0a.woff2,SourceCodePro-Regular-8badfe75.ttf.woff2,SourceCodePro-Semibold-aa29a496.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2"href="../../../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../../../static.files/normalize-9960930a.css"><link rel="stylesheet" href="../../../static.files/rustdoc-17e0aaed.css"><meta name="rustdoc-vars" data-root-path="../../../" data-static-root-path="../../../static.files/" data-current-crate="jellytau_lib" data-themes="" data-resource-suffix="" data-rustdoc-version="1.97.1 (8bab26f4f 2026-07-14)" data-channel="1.97.1" data-search-js="search-fd9372ac.js" data-stringdex-js="stringdex-2da4960a.js" data-settings-js="settings-170eb4bf.js" ><script src="../../../static.files/storage-41dd4d93.js"></script><script defer src="../sidebar-items.js"></script><script defer src="../../../static.files/main-fcd733ba.js"></script><noscript><link rel="stylesheet" href="../../../static.files/noscript-f7c3ffd8.css"></noscript><link rel="alternate icon" type="image/png" href="../../../static.files/favicon-32x32-eab170b8.png"><link rel="icon" type="image/svg+xml" href="../../../static.files/favicon-044be391.svg"></head><body class="rustdoc mod"><a class="skip-main-content" href="#main-content">Skip to main content</a><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><rustdoc-topbar><h2><a href="#">Module catalog</a></h2></rustdoc-topbar><nav class="sidebar"><div class="sidebar-crate"><h2><a href="../../../jellytau_lib/index.html">jellytau_<wbr>lib</a><span class="version">0.11.1</span></h2></div><div class="sidebar-elems"><section id="rustdoc-toc"><h2 class="location"><a href="#">Module catalog</a></h2><h3><a href="#structs">Module Items</a></h3><ul class="block"><li><a href="#structs" title="Structs">Structs</a></li><li><a href="#constants" title="Constants">Constants</a></li><li><a href="#statics" title="Statics">Statics</a></li><li><a href="#functions" title="Functions">Functions</a></li></ul></section><div id="rustdoc-modnav"><h2><a href="../index.html">In jellytau_<wbr>lib::<wbr>commands</a></h2></div></div></nav><div class="sidebar-resizer" title="Drag to resize sidebar"></div><main><div class="width-limiter"><section id="main-content" class="content" tabindex="-1"><div class="main-heading"><div class="rustdoc-breadcrumbs"><a href="../../index.html">jellytau_lib</a>::<wbr><a href="../index.html">commands</a></div><h1>Module <span>catalog</span>&nbsp;<button id="copy-path" title="Copy item path to clipboard">Copy item path</button></h1><rustdoc-toolbar></rustdoc-toolbar><span class="sub-heading"><a class="src" href="../../../src/jellytau_lib/commands/catalog.rs.html#1-1147">Source</a> </span></div><details class="toggle top-doc" open><summary class="hideme"><span>Expand description</span></summary><div class="docblock"><p>Tauri commands for the offline “browse &amp; queue” feature.</p>
<p>TRACES: UR-002, UR-007, UR-024 | JA-004, JA-016 | DR-012, DR-027</p>
<p>Two backend pieces support browsing the full server catalog while offline
and queueing downloads that fire on reconnect:</p>
<ul>
<li><a href="fn.sync_full_catalog.html" title="fn jellytau_lib::commands::catalog::sync_full_catalog"><code>sync_full_catalog</code></a> walks every library while online and persists all
items to the offline cache so the whole catalog is browsable (greyed out)
offline. It reuses [<code>HybridRepository::cache_items_from_server</code>], which in
turn reuses <code>OfflineRepository::save_to_cache</code> (sets <code>synced_at</code>, which is
what <code>get_items</code> branch 3 serves offline).</li>
<li><a href="fn.resume_queued_downloads.html" title="fn jellytau_lib::commands::catalog::resume_queued_downloads"><code>resume_queued_downloads</code></a> resolves and pumps the <code>pending</code> download rows
that were queued offline (they have <code>stream_url IS NULL</code>), mirroring the
heal-and-pump pattern in <code>player_preload_upcoming</code>.</li>
</ul>
</div></details><h2 id="structs" class="section-header">Structs<a href="#structs" class="anchor">§</a></h2><dl class="item-table"><dt><a class="struct" href="struct.CatalogIndexEvent.html" title="struct jellytau_lib::commands::catalog::CatalogIndexEvent">Catalog<wbr>Index<wbr>Event</a></dt><dd>Progress of a background index pass, for the staleness hint in the UI.</dd><dt><a class="struct" href="struct.CatalogSyncResult.html" title="struct jellytau_lib::commands::catalog::CatalogSyncResult">Catalog<wbr>Sync<wbr>Result</a></dt><dt><a class="struct" href="struct.CatalogSyncStatus.html" title="struct jellytau_lib::commands::catalog::CatalogSyncStatus">Catalog<wbr>Sync<wbr>Status</a></dt><dt><a class="struct" href="struct.IndexPassGuard.html" title="struct jellytau_lib::commands::catalog::IndexPassGuard">Index<wbr>Pass<wbr>Guard</a><span title="Restricted Visibility">&nbsp;🔒</span> </dt><dd>Clears <a href="static.INDEX_IN_PROGRESS.html" title="static jellytau_lib::commands::catalog::INDEX_IN_PROGRESS"><code>INDEX_IN_PROGRESS</code></a> however the pass leaves — including on the <code>?</code>
early return when <code>get_libraries</code> fails, which a plain store at the end of
the function would leak.</dd><dt><a class="struct" href="struct.ResumeQueuedResult.html" title="struct jellytau_lib::commands::catalog::ResumeQueuedResult">Resume<wbr>Queued<wbr>Result</a></dt></dl><h2 id="constants" class="section-header">Constants<a href="#constants" class="anchor">§</a></h2><dl class="item-table"><dt><a class="constant" href="constant.CATALOG_INDEX_EVENT.html" title="constant jellytau_lib::commands::catalog::CATALOG_INDEX_EVENT">CATALOG_<wbr>INDEX_<wbr>EVENT</a></dt><dd>Kebab-case, per the projects event convention.</dd><dt><a class="constant" href="constant.CATALOG_INDEX_FIRST_CHECK.html" title="constant jellytau_lib::commands::catalog::CATALOG_INDEX_FIRST_CHECK">CATALOG_<wbr>INDEX_<wbr>FIRST_<wbr>CHECK</a><span title="Restricted Visibility">&nbsp;🔒</span> </dt><dd>Delay before the first staleness check, to let sign-in complete and the
repository be registered. Without it the first check runs against an empty
repository manager and a fresh install would sit unindexed until the next
tick.</dd><dt><a class="constant" href="constant.CATALOG_INDEX_TICK.html" title="constant jellytau_lib::commands::catalog::CATALOG_INDEX_TICK">CATALOG_<wbr>INDEX_<wbr>TICK</a><span title="Restricted Visibility">&nbsp;🔒</span> </dt><dd>How often the scheduler wakes to <em>check</em> staleness. Far shorter than the TTL
because a tick is nearly free — one indexed <code>app_settings</code> lookup — and it is
what makes the indexer responsive to events it cannot subscribe to: signing
in, and coming back online. The TTL, not the tick, decides whether a crawl
actually happens.</dd><dt><a class="constant" href="constant.CATALOG_INDEX_TTL.html" title="constant jellytau_lib::commands::catalog::CATALOG_INDEX_TTL">CATALOG_<wbr>INDEX_<wbr>TTL</a><span title="Restricted Visibility">&nbsp;🔒</span> </dt><dd>How long an index stays fresh before a re-index is due.</dd><dt><a class="constant" href="constant.CATALOG_ITEM_TYPES.html" title="constant jellytau_lib::commands::catalog::CATALOG_ITEM_TYPES">CATALOG_<wbr>ITEM_<wbr>TYPES</a><span title="Restricted Visibility">&nbsp;🔒</span> </dt><dd>Item types worth caching for offline browsing: containers the library
landing pages render plus the playable leaves users queue for download.
<code>MusicArtist</code> and <code>Playlist</code> are here because search groups results by them
(UR-060s Artists group). Without them in the crawl, the local index can
never answer an artist query and those groups can only ever be filled by the
server leg. Keep this in step with what <code>prune_stale_catalog</code> is allowed to
sweep — the crawl is only authoritative for the types it asks for.</dd><dt><a class="constant" href="constant.LAST_CATALOG_SYNC_KEY.html" title="constant jellytau_lib::commands::catalog::LAST_CATALOG_SYNC_KEY">LAST_<wbr>CATALOG_<wbr>SYNC_<wbr>KEY</a><span title="Restricted Visibility">&nbsp;🔒</span> </dt><dd>app_settings key holding the RFC-3339 timestamp of the last successful
full-catalog sync.</dd><dt><a class="constant" href="constant.VIDEO_ITEM_TYPES.html" title="constant jellytau_lib::commands::catalog::VIDEO_ITEM_TYPES">VIDEO_<wbr>ITEM_<wbr>TYPES</a><span title="Restricted Visibility">&nbsp;🔒</span> </dt><dd>Jellyfin item types whose download is a <em>video</em> stream rather than an audio
one. The download queue stores an opaque <code>media_type</code> (audio/video); this
is where the taxonomy that produces it lives, so the frontend never has to
know which item types are video.</dd></dl><h2 id="statics" class="section-header">Statics<a href="#statics" class="anchor">§</a></h2><dl class="item-table"><dt><a class="static" href="static.INDEX_IN_PROGRESS.html" title="static jellytau_lib::commands::catalog::INDEX_IN_PROGRESS">INDEX_<wbr>IN_<wbr>PROGRESS</a><span title="Restricted Visibility">&nbsp;🔒</span> </dt><dd>Guards against two passes running at once. Replaces the frontends
<code>syncInProgress</code> boolean in <code>offlineCatalog.ts</code>, which could not see a pass
started by the scheduler.</dd></dl><h2 id="functions" class="section-header">Functions<a href="#functions" class="anchor">§</a></h2><dl class="item-table"><dt><a class="fn" href="fn.catalog_sync_status.html" title="fn jellytau_lib::commands::catalog::catalog_sync_status">catalog_<wbr>sync_<wbr>status</a></dt><dd>Report the last-synced timestamp so the UI can show a hint / decide whether
to trigger a fresh sync.</dd><dt><a class="fn" href="fn.index_is_due.html" title="fn jellytau_lib::commands::catalog::index_is_due">index_<wbr>is_<wbr>due</a><span title="Restricted Visibility">&nbsp;🔒</span> </dt><dd>Whether an index pass is due, given when one last completed.</dd><dt><a class="fn" href="fn.maybe_run_scheduled_pass.html" title="fn jellytau_lib::commands::catalog::maybe_run_scheduled_pass">maybe_<wbr>run_<wbr>scheduled_<wbr>pass</a><span title="Restricted Visibility">&nbsp;🔒</span> </dt><dd>One scheduler tick: check the preconditions, then index if due.</dd><dt><a class="fn" href="fn.read_last_sync.html" title="fn jellytau_lib::commands::catalog::read_last_sync">read_<wbr>last_<wbr>sync</a><span title="Restricted Visibility">&nbsp;🔒</span> </dt><dd>Read the last-sync timestamp straight from <code>app_settings</code>.</dd><dt><a class="fn" href="fn.requeue_mistyped_video_downloads.html" title="fn jellytau_lib::commands::catalog::requeue_mistyped_video_downloads">requeue_<wbr>mistyped_<wbr>video_<wbr>downloads</a><span title="Restricted Visibility">&nbsp;🔒</span> </dt><dd>Requeue video downloads that were fetched as audio.</dd><dt><a class="fn" href="fn.resolve_pending_download_urls.html" title="fn jellytau_lib::commands::catalog::resolve_pending_download_urls">resolve_<wbr>pending_<wbr>download_<wbr>urls</a><span title="Restricted Visibility">&nbsp;🔒</span> </dt><dd>Core of <a href="fn.resume_queued_downloads.html" title="fn jellytau_lib::commands::catalog::resume_queued_downloads"><code>resume_queued_downloads</code></a>, factored out for testing: select every
<code>pending</code>/<code>stream_url IS NULL</code> row, resolve each via <code>resolve</code> (returning
<code>None</code> leaves the row pending), and heal the row so the pump can start it.
The <code>resolve</code> closure receives <code>(item_id, media_type, quality_preset)</code>.</dd><dt><a class="fn" href="fn.resume_queued_downloads.html" title="fn jellytau_lib::commands::catalog::resume_queued_downloads">resume_<wbr>queued_<wbr>downloads</a></dt><dd>Resolve the stream URL for every download row that was queued while offline
(<code>status = 'pending' AND stream_url IS NULL</code>), then pump the queue so they
start. Call this on reconnect.</dd><dt><a class="fn" href="fn.run_index_pass.html" title="fn jellytau_lib::commands::catalog::run_index_pass">run_<wbr>index_<wbr>pass</a><span title="Restricted Visibility">&nbsp;🔒</span> </dt><dd>One full-catalog indexing pass, shared by the <a href="fn.sync_full_catalog.html" title="fn jellytau_lib::commands::catalog::sync_full_catalog"><code>sync_full_catalog</code></a> command
and the background scheduler (DR-109) so there is exactly one implementation
and one concurrency guard.</dd><dt><a class="fn" href="fn.set_show_server_catalog.html" title="fn jellytau_lib::commands::catalog::set_show_server_catalog">set_<wbr>show_<wbr>server_<wbr>catalog</a></dt><dd>Control whether offline library queries reveal the full synced catalog
(greyed-out, non-downloaded media) or only downloaded/local media.</dd><dt><a class="fn" href="fn.spawn_catalog_indexer.html" title="fn jellytau_lib::commands::catalog::spawn_catalog_indexer">spawn_<wbr>catalog_<wbr>indexer</a></dt><dd>Start the background catalog indexer.</dd><dt><a class="fn" href="fn.sync_full_catalog.html" title="fn jellytau_lib::commands::catalog::sync_full_catalog">sync_<wbr>full_<wbr>catalog</a></dt><dd>Walk every library on the server and persist all items to the offline cache
so the full catalog is browsable offline (greyed out when not downloaded).</dd></dl></section></div></main></body></html>
@@ -0,0 +1 @@
window.SIDEBAR_ITEMS = {"constant":["CATALOG_INDEX_EVENT","CATALOG_INDEX_FIRST_CHECK","CATALOG_INDEX_TICK","CATALOG_INDEX_TTL","CATALOG_ITEM_TYPES","LAST_CATALOG_SYNC_KEY","VIDEO_ITEM_TYPES"],"fn":["catalog_sync_status","index_is_due","maybe_run_scheduled_pass","read_last_sync","requeue_mistyped_video_downloads","resolve_pending_download_urls","resume_queued_downloads","run_index_pass","set_show_server_catalog","spawn_catalog_indexer","sync_full_catalog"],"static":["INDEX_IN_PROGRESS"],"struct":["CatalogIndexEvent","CatalogSyncResult","CatalogSyncStatus","IndexPassGuard","ResumeQueuedResult"]};
@@ -0,0 +1,4 @@
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="Guards against two passes running at once. Replaces the frontends `syncInProgress` boolean in `offlineCatalog.ts`, which could not see a pass started by the scheduler."><title>INDEX_IN_PROGRESS in jellytau_lib::commands::catalog - Rust</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-6b053e98.ttf.woff2,FiraSans-Italic-81dc35de.woff2,FiraSans-Regular-0fe48ade.woff2,FiraSans-MediumItalic-ccf7e434.woff2,FiraSans-Medium-e1aa3f0a.woff2,SourceCodePro-Regular-8badfe75.ttf.woff2,SourceCodePro-Semibold-aa29a496.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2"href="../../../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../../../static.files/normalize-9960930a.css"><link rel="stylesheet" href="../../../static.files/rustdoc-17e0aaed.css"><meta name="rustdoc-vars" data-root-path="../../../" data-static-root-path="../../../static.files/" data-current-crate="jellytau_lib" data-themes="" data-resource-suffix="" data-rustdoc-version="1.97.1 (8bab26f4f 2026-07-14)" data-channel="1.97.1" data-search-js="search-fd9372ac.js" data-stringdex-js="stringdex-2da4960a.js" data-settings-js="settings-170eb4bf.js" ><script src="../../../static.files/storage-41dd4d93.js"></script><script defer src="sidebar-items.js"></script><script defer src="../../../static.files/main-fcd733ba.js"></script><noscript><link rel="stylesheet" href="../../../static.files/noscript-f7c3ffd8.css"></noscript><link rel="alternate icon" type="image/png" href="../../../static.files/favicon-32x32-eab170b8.png"><link rel="icon" type="image/svg+xml" href="../../../static.files/favicon-044be391.svg"></head><body class="rustdoc static"><a class="skip-main-content" href="#main-content">Skip to main content</a><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><rustdoc-topbar><h2><a href="#">INDEX_IN_PROGRESS</a></h2></rustdoc-topbar><nav class="sidebar"><div class="sidebar-crate"><h2><a href="../../../jellytau_lib/index.html">jellytau_<wbr>lib</a><span class="version">0.11.1</span></h2></div><div class="sidebar-elems"><div id="rustdoc-modnav"><h2><a href="index.html">In jellytau_<wbr>lib::<wbr>commands::<wbr>catalog</a></h2></div></div></nav><div class="sidebar-resizer" title="Drag to resize sidebar"></div><main><div class="width-limiter"><section id="main-content" class="content" tabindex="-1"><div class="main-heading"><div class="rustdoc-breadcrumbs"><a href="../../index.html">jellytau_lib</a>::<wbr><a href="../index.html">commands</a>::<wbr><a href="index.html">catalog</a></div><h1>Static <span class="static">INDEX_<wbr>IN_<wbr>PROGRESS</span>&nbsp;<button id="copy-path" title="Copy item path to clipboard">Copy item path</button></h1><rustdoc-toolbar></rustdoc-toolbar><span class="sub-heading"><a class="src" href="../../../src/jellytau_lib/commands/catalog.rs.html#62">Source</a> </span></div><pre class="rust item-decl"><code>static INDEX_IN_PROGRESS: <a class="type" href="https://doc.rust-lang.org/1.97.1/core/sync/atomic/type.AtomicBool.html" title="type core::sync::atomic::AtomicBool">AtomicBool</a></code></pre><details class="toggle top-doc" open><summary class="hideme"><span>Expand description</span></summary><div class="docblock"><p>Guards against two passes running at once. Replaces the frontends
<code>syncInProgress</code> boolean in <code>offlineCatalog.ts</code>, which could not see a pass
started by the scheduler.</p>
</div></details></section></div></main></body></html>
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -0,0 +1,4 @@
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="Check if the server is currently reachable"><title>connectivity_check_server in jellytau_lib::commands::connectivity - Rust</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-6b053e98.ttf.woff2,FiraSans-Italic-81dc35de.woff2,FiraSans-Regular-0fe48ade.woff2,FiraSans-MediumItalic-ccf7e434.woff2,FiraSans-Medium-e1aa3f0a.woff2,SourceCodePro-Regular-8badfe75.ttf.woff2,SourceCodePro-Semibold-aa29a496.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2"href="../../../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../../../static.files/normalize-9960930a.css"><link rel="stylesheet" href="../../../static.files/rustdoc-17e0aaed.css"><meta name="rustdoc-vars" data-root-path="../../../" data-static-root-path="../../../static.files/" data-current-crate="jellytau_lib" data-themes="" data-resource-suffix="" data-rustdoc-version="1.97.1 (8bab26f4f 2026-07-14)" data-channel="1.97.1" data-search-js="search-fd9372ac.js" data-stringdex-js="stringdex-2da4960a.js" data-settings-js="settings-170eb4bf.js" ><script src="../../../static.files/storage-41dd4d93.js"></script><script defer src="sidebar-items.js"></script><script defer src="../../../static.files/main-fcd733ba.js"></script><noscript><link rel="stylesheet" href="../../../static.files/noscript-f7c3ffd8.css"></noscript><link rel="alternate icon" type="image/png" href="../../../static.files/favicon-32x32-eab170b8.png"><link rel="icon" type="image/svg+xml" href="../../../static.files/favicon-044be391.svg"></head><body class="rustdoc fn"><a class="skip-main-content" href="#main-content">Skip to main content</a><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><rustdoc-topbar><h2><a href="#">connectivity_check_server</a></h2></rustdoc-topbar><nav class="sidebar"><div class="sidebar-crate"><h2><a href="../../../jellytau_lib/index.html">jellytau_<wbr>lib</a><span class="version">0.11.1</span></h2></div><div class="sidebar-elems"><div id="rustdoc-modnav"><h2><a href="index.html">In jellytau_<wbr>lib::<wbr>commands::<wbr>connectivity</a></h2></div></div></nav><div class="sidebar-resizer" title="Drag to resize sidebar"></div><main><div class="width-limiter"><section id="main-content" class="content" tabindex="-1"><div class="main-heading"><div class="rustdoc-breadcrumbs"><a href="../../index.html">jellytau_lib</a>::<wbr><a href="../index.html">commands</a>::<wbr><a href="index.html">connectivity</a></div><h1>Function <span class="fn">connectivity_<wbr>check_<wbr>server</span>&nbsp;<button id="copy-path" title="Copy item path to clipboard">Copy item path</button></h1><rustdoc-toolbar></rustdoc-toolbar><span class="sub-heading"><a class="src" href="../../../src/jellytau_lib/commands/connectivity.rs.html#15-20">Source</a> </span></div><pre class="rust item-decl"><code>pub async fn connectivity_check_server(
state: State&lt;'_, <a class="struct" href="struct.ConnectivityMonitorWrapper.html" title="struct jellytau_lib::commands::connectivity::ConnectivityMonitorWrapper">ConnectivityMonitorWrapper</a>&gt;,
) -&gt; <a class="enum" href="https://doc.rust-lang.org/1.97.1/core/result/enum.Result.html" title="enum core::result::Result">Result</a>&lt;<a class="primitive" href="https://doc.rust-lang.org/1.97.1/std/primitive.bool.html">bool</a>, <a class="struct" href="https://doc.rust-lang.org/1.97.1/alloc/string/struct.String.html" title="struct alloc::string::String">String</a>&gt;</code></pre><details class="toggle top-doc" open><summary class="hideme"><span>Expand description</span></summary><div class="docblock"><p>Check if the server is currently reachable</p>
</div></details></section></div></main></body></html>
@@ -0,0 +1,4 @@
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="Get the current connectivity status"><title>connectivity_get_status in jellytau_lib::commands::connectivity - Rust</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-6b053e98.ttf.woff2,FiraSans-Italic-81dc35de.woff2,FiraSans-Regular-0fe48ade.woff2,FiraSans-MediumItalic-ccf7e434.woff2,FiraSans-Medium-e1aa3f0a.woff2,SourceCodePro-Regular-8badfe75.ttf.woff2,SourceCodePro-Semibold-aa29a496.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2"href="../../../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../../../static.files/normalize-9960930a.css"><link rel="stylesheet" href="../../../static.files/rustdoc-17e0aaed.css"><meta name="rustdoc-vars" data-root-path="../../../" data-static-root-path="../../../static.files/" data-current-crate="jellytau_lib" data-themes="" data-resource-suffix="" data-rustdoc-version="1.97.1 (8bab26f4f 2026-07-14)" data-channel="1.97.1" data-search-js="search-fd9372ac.js" data-stringdex-js="stringdex-2da4960a.js" data-settings-js="settings-170eb4bf.js" ><script src="../../../static.files/storage-41dd4d93.js"></script><script defer src="sidebar-items.js"></script><script defer src="../../../static.files/main-fcd733ba.js"></script><noscript><link rel="stylesheet" href="../../../static.files/noscript-f7c3ffd8.css"></noscript><link rel="alternate icon" type="image/png" href="../../../static.files/favicon-32x32-eab170b8.png"><link rel="icon" type="image/svg+xml" href="../../../static.files/favicon-044be391.svg"></head><body class="rustdoc fn"><a class="skip-main-content" href="#main-content">Skip to main content</a><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><rustdoc-topbar><h2><a href="#">connectivity_get_status</a></h2></rustdoc-topbar><nav class="sidebar"><div class="sidebar-crate"><h2><a href="../../../jellytau_lib/index.html">jellytau_<wbr>lib</a><span class="version">0.11.1</span></h2></div><div class="sidebar-elems"><div id="rustdoc-modnav"><h2><a href="index.html">In jellytau_<wbr>lib::<wbr>commands::<wbr>connectivity</a></h2></div></div></nav><div class="sidebar-resizer" title="Drag to resize sidebar"></div><main><div class="width-limiter"><section id="main-content" class="content" tabindex="-1"><div class="main-heading"><div class="rustdoc-breadcrumbs"><a href="../../index.html">jellytau_lib</a>::<wbr><a href="../index.html">commands</a>::<wbr><a href="index.html">connectivity</a></div><h1>Function <span class="fn">connectivity_<wbr>get_<wbr>status</span>&nbsp;<button id="copy-path" title="Copy item path to clipboard">Copy item path</button></h1><rustdoc-toolbar></rustdoc-toolbar><span class="sub-heading"><a class="src" href="../../../src/jellytau_lib/commands/connectivity.rs.html#37-42">Source</a> </span></div><pre class="rust item-decl"><code>pub async fn connectivity_get_status(
state: State&lt;'_, <a class="struct" href="struct.ConnectivityMonitorWrapper.html" title="struct jellytau_lib::commands::connectivity::ConnectivityMonitorWrapper">ConnectivityMonitorWrapper</a>&gt;,
) -&gt; <a class="enum" href="https://doc.rust-lang.org/1.97.1/core/result/enum.Result.html" title="enum core::result::Result">Result</a>&lt;<a class="struct" href="../../connectivity/struct.ConnectivityStatus.html" title="struct jellytau_lib::connectivity::ConnectivityStatus">ConnectivityStatus</a>, <a class="struct" href="https://doc.rust-lang.org/1.97.1/alloc/string/struct.String.html" title="struct alloc::string::String">String</a>&gt;</code></pre><details class="toggle top-doc" open><summary class="hideme"><span>Expand description</span></summary><div class="docblock"><p>Get the current connectivity status</p>
</div></details></section></div></main></body></html>
@@ -0,0 +1,4 @@
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="Mark the server as reachable (called after successful API calls)"><title>connectivity_mark_reachable in jellytau_lib::commands::connectivity - Rust</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-6b053e98.ttf.woff2,FiraSans-Italic-81dc35de.woff2,FiraSans-Regular-0fe48ade.woff2,FiraSans-MediumItalic-ccf7e434.woff2,FiraSans-Medium-e1aa3f0a.woff2,SourceCodePro-Regular-8badfe75.ttf.woff2,SourceCodePro-Semibold-aa29a496.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2"href="../../../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../../../static.files/normalize-9960930a.css"><link rel="stylesheet" href="../../../static.files/rustdoc-17e0aaed.css"><meta name="rustdoc-vars" data-root-path="../../../" data-static-root-path="../../../static.files/" data-current-crate="jellytau_lib" data-themes="" data-resource-suffix="" data-rustdoc-version="1.97.1 (8bab26f4f 2026-07-14)" data-channel="1.97.1" data-search-js="search-fd9372ac.js" data-stringdex-js="stringdex-2da4960a.js" data-settings-js="settings-170eb4bf.js" ><script src="../../../static.files/storage-41dd4d93.js"></script><script defer src="sidebar-items.js"></script><script defer src="../../../static.files/main-fcd733ba.js"></script><noscript><link rel="stylesheet" href="../../../static.files/noscript-f7c3ffd8.css"></noscript><link rel="alternate icon" type="image/png" href="../../../static.files/favicon-32x32-eab170b8.png"><link rel="icon" type="image/svg+xml" href="../../../static.files/favicon-044be391.svg"></head><body class="rustdoc fn"><a class="skip-main-content" href="#main-content">Skip to main content</a><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><rustdoc-topbar><h2><a href="#">connectivity_mark_reachable</a></h2></rustdoc-topbar><nav class="sidebar"><div class="sidebar-crate"><h2><a href="../../../jellytau_lib/index.html">jellytau_<wbr>lib</a><span class="version">0.11.1</span></h2></div><div class="sidebar-elems"><div id="rustdoc-modnav"><h2><a href="index.html">In jellytau_<wbr>lib::<wbr>commands::<wbr>connectivity</a></h2></div></div></nav><div class="sidebar-resizer" title="Drag to resize sidebar"></div><main><div class="width-limiter"><section id="main-content" class="content" tabindex="-1"><div class="main-heading"><div class="rustdoc-breadcrumbs"><a href="../../index.html">jellytau_lib</a>::<wbr><a href="../index.html">commands</a>::<wbr><a href="index.html">connectivity</a></div><h1>Function <span class="fn">connectivity_<wbr>mark_<wbr>reachable</span>&nbsp;<button id="copy-path" title="Copy item path to clipboard">Copy item path</button></h1><rustdoc-toolbar></rustdoc-toolbar><span class="sub-heading"><a class="src" href="../../../src/jellytau_lib/commands/connectivity.rs.html#69-75">Source</a> </span></div><pre class="rust item-decl"><code>pub async fn connectivity_mark_reachable(
state: State&lt;'_, <a class="struct" href="struct.ConnectivityMonitorWrapper.html" title="struct jellytau_lib::commands::connectivity::ConnectivityMonitorWrapper">ConnectivityMonitorWrapper</a>&gt;,
) -&gt; <a class="enum" href="https://doc.rust-lang.org/1.97.1/core/result/enum.Result.html" title="enum core::result::Result">Result</a>&lt;<a class="primitive" href="https://doc.rust-lang.org/1.97.1/std/primitive.unit.html">()</a>, <a class="struct" href="https://doc.rust-lang.org/1.97.1/alloc/string/struct.String.html" title="struct alloc::string::String">String</a>&gt;</code></pre><details class="toggle top-doc" open><summary class="hideme"><span>Expand description</span></summary><div class="docblock"><p>Mark the server as reachable (called after successful API calls)</p>
</div></details></section></div></main></body></html>
@@ -0,0 +1,5 @@
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="Mark the server as unreachable (called after failed API calls)"><title>connectivity_mark_unreachable in jellytau_lib::commands::connectivity - Rust</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-6b053e98.ttf.woff2,FiraSans-Italic-81dc35de.woff2,FiraSans-Regular-0fe48ade.woff2,FiraSans-MediumItalic-ccf7e434.woff2,FiraSans-Medium-e1aa3f0a.woff2,SourceCodePro-Regular-8badfe75.ttf.woff2,SourceCodePro-Semibold-aa29a496.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2"href="../../../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../../../static.files/normalize-9960930a.css"><link rel="stylesheet" href="../../../static.files/rustdoc-17e0aaed.css"><meta name="rustdoc-vars" data-root-path="../../../" data-static-root-path="../../../static.files/" data-current-crate="jellytau_lib" data-themes="" data-resource-suffix="" data-rustdoc-version="1.97.1 (8bab26f4f 2026-07-14)" data-channel="1.97.1" data-search-js="search-fd9372ac.js" data-stringdex-js="stringdex-2da4960a.js" data-settings-js="settings-170eb4bf.js" ><script src="../../../static.files/storage-41dd4d93.js"></script><script defer src="sidebar-items.js"></script><script defer src="../../../static.files/main-fcd733ba.js"></script><noscript><link rel="stylesheet" href="../../../static.files/noscript-f7c3ffd8.css"></noscript><link rel="alternate icon" type="image/png" href="../../../static.files/favicon-32x32-eab170b8.png"><link rel="icon" type="image/svg+xml" href="../../../static.files/favicon-044be391.svg"></head><body class="rustdoc fn"><a class="skip-main-content" href="#main-content">Skip to main content</a><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><rustdoc-topbar><h2><a href="#">connectivity_mark_unreachable</a></h2></rustdoc-topbar><nav class="sidebar"><div class="sidebar-crate"><h2><a href="../../../jellytau_lib/index.html">jellytau_<wbr>lib</a><span class="version">0.11.1</span></h2></div><div class="sidebar-elems"><div id="rustdoc-modnav"><h2><a href="index.html">In jellytau_<wbr>lib::<wbr>commands::<wbr>connectivity</a></h2></div></div></nav><div class="sidebar-resizer" title="Drag to resize sidebar"></div><main><div class="width-limiter"><section id="main-content" class="content" tabindex="-1"><div class="main-heading"><div class="rustdoc-breadcrumbs"><a href="../../index.html">jellytau_lib</a>::<wbr><a href="../index.html">commands</a>::<wbr><a href="index.html">connectivity</a></div><h1>Function <span class="fn">connectivity_<wbr>mark_<wbr>unreachable</span>&nbsp;<button id="copy-path" title="Copy item path to clipboard">Copy item path</button></h1><rustdoc-toolbar></rustdoc-toolbar><span class="sub-heading"><a class="src" href="../../../src/jellytau_lib/commands/connectivity.rs.html#80-87">Source</a> </span></div><pre class="rust item-decl"><code>pub async fn connectivity_mark_unreachable(
error: <a class="enum" href="https://doc.rust-lang.org/1.97.1/core/option/enum.Option.html" title="enum core::option::Option">Option</a>&lt;<a class="struct" href="https://doc.rust-lang.org/1.97.1/alloc/string/struct.String.html" title="struct alloc::string::String">String</a>&gt;,
state: State&lt;'_, <a class="struct" href="struct.ConnectivityMonitorWrapper.html" title="struct jellytau_lib::commands::connectivity::ConnectivityMonitorWrapper">ConnectivityMonitorWrapper</a>&gt;,
) -&gt; <a class="enum" href="https://doc.rust-lang.org/1.97.1/core/result/enum.Result.html" title="enum core::result::Result">Result</a>&lt;<a class="primitive" href="https://doc.rust-lang.org/1.97.1/std/primitive.unit.html">()</a>, <a class="struct" href="https://doc.rust-lang.org/1.97.1/alloc/string/struct.String.html" title="struct alloc::string::String">String</a>&gt;</code></pre><details class="toggle top-doc" open><summary class="hideme"><span>Expand description</span></summary><div class="docblock"><p>Mark the server as unreachable (called after failed API calls)</p>
</div></details></section></div></main></body></html>
@@ -0,0 +1,5 @@
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="Set the server URL and trigger an immediate check"><title>connectivity_set_server_url in jellytau_lib::commands::connectivity - Rust</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-6b053e98.ttf.woff2,FiraSans-Italic-81dc35de.woff2,FiraSans-Regular-0fe48ade.woff2,FiraSans-MediumItalic-ccf7e434.woff2,FiraSans-Medium-e1aa3f0a.woff2,SourceCodePro-Regular-8badfe75.ttf.woff2,SourceCodePro-Semibold-aa29a496.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2"href="../../../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../../../static.files/normalize-9960930a.css"><link rel="stylesheet" href="../../../static.files/rustdoc-17e0aaed.css"><meta name="rustdoc-vars" data-root-path="../../../" data-static-root-path="../../../static.files/" data-current-crate="jellytau_lib" data-themes="" data-resource-suffix="" data-rustdoc-version="1.97.1 (8bab26f4f 2026-07-14)" data-channel="1.97.1" data-search-js="search-fd9372ac.js" data-stringdex-js="stringdex-2da4960a.js" data-settings-js="settings-170eb4bf.js" ><script src="../../../static.files/storage-41dd4d93.js"></script><script defer src="sidebar-items.js"></script><script defer src="../../../static.files/main-fcd733ba.js"></script><noscript><link rel="stylesheet" href="../../../static.files/noscript-f7c3ffd8.css"></noscript><link rel="alternate icon" type="image/png" href="../../../static.files/favicon-32x32-eab170b8.png"><link rel="icon" type="image/svg+xml" href="../../../static.files/favicon-044be391.svg"></head><body class="rustdoc fn"><a class="skip-main-content" href="#main-content">Skip to main content</a><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><rustdoc-topbar><h2><a href="#">connectivity_set_server_url</a></h2></rustdoc-topbar><nav class="sidebar"><div class="sidebar-crate"><h2><a href="../../../jellytau_lib/index.html">jellytau_<wbr>lib</a><span class="version">0.11.1</span></h2></div><div class="sidebar-elems"><div id="rustdoc-modnav"><h2><a href="index.html">In jellytau_<wbr>lib::<wbr>commands::<wbr>connectivity</a></h2></div></div></nav><div class="sidebar-resizer" title="Drag to resize sidebar"></div><main><div class="width-limiter"><section id="main-content" class="content" tabindex="-1"><div class="main-heading"><div class="rustdoc-breadcrumbs"><a href="../../index.html">jellytau_lib</a>::<wbr><a href="../index.html">commands</a>::<wbr><a href="index.html">connectivity</a></div><h1>Function <span class="fn">connectivity_<wbr>set_<wbr>server_<wbr>url</span>&nbsp;<button id="copy-path" title="Copy item path to clipboard">Copy item path</button></h1><rustdoc-toolbar></rustdoc-toolbar><span class="sub-heading"><a class="src" href="../../../src/jellytau_lib/commands/connectivity.rs.html#25-32">Source</a> </span></div><pre class="rust item-decl"><code>pub async fn connectivity_set_server_url(
url: <a class="struct" href="https://doc.rust-lang.org/1.97.1/alloc/string/struct.String.html" title="struct alloc::string::String">String</a>,
state: State&lt;'_, <a class="struct" href="struct.ConnectivityMonitorWrapper.html" title="struct jellytau_lib::commands::connectivity::ConnectivityMonitorWrapper">ConnectivityMonitorWrapper</a>&gt;,
) -&gt; <a class="enum" href="https://doc.rust-lang.org/1.97.1/core/result/enum.Result.html" title="enum core::result::Result">Result</a>&lt;<a class="primitive" href="https://doc.rust-lang.org/1.97.1/std/primitive.unit.html">()</a>, <a class="struct" href="https://doc.rust-lang.org/1.97.1/alloc/string/struct.String.html" title="struct alloc::string::String">String</a>&gt;</code></pre><details class="toggle top-doc" open><summary class="hideme"><span>Expand description</span></summary><div class="docblock"><p>Set the server URL and trigger an immediate check</p>
</div></details></section></div></main></body></html>
@@ -0,0 +1,4 @@
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="Start monitoring connectivity with adaptive polling"><title>connectivity_start_monitoring in jellytau_lib::commands::connectivity - Rust</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-6b053e98.ttf.woff2,FiraSans-Italic-81dc35de.woff2,FiraSans-Regular-0fe48ade.woff2,FiraSans-MediumItalic-ccf7e434.woff2,FiraSans-Medium-e1aa3f0a.woff2,SourceCodePro-Regular-8badfe75.ttf.woff2,SourceCodePro-Semibold-aa29a496.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2"href="../../../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../../../static.files/normalize-9960930a.css"><link rel="stylesheet" href="../../../static.files/rustdoc-17e0aaed.css"><meta name="rustdoc-vars" data-root-path="../../../" data-static-root-path="../../../static.files/" data-current-crate="jellytau_lib" data-themes="" data-resource-suffix="" data-rustdoc-version="1.97.1 (8bab26f4f 2026-07-14)" data-channel="1.97.1" data-search-js="search-fd9372ac.js" data-stringdex-js="stringdex-2da4960a.js" data-settings-js="settings-170eb4bf.js" ><script src="../../../static.files/storage-41dd4d93.js"></script><script defer src="sidebar-items.js"></script><script defer src="../../../static.files/main-fcd733ba.js"></script><noscript><link rel="stylesheet" href="../../../static.files/noscript-f7c3ffd8.css"></noscript><link rel="alternate icon" type="image/png" href="../../../static.files/favicon-32x32-eab170b8.png"><link rel="icon" type="image/svg+xml" href="../../../static.files/favicon-044be391.svg"></head><body class="rustdoc fn"><a class="skip-main-content" href="#main-content">Skip to main content</a><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><rustdoc-topbar><h2><a href="#">connectivity_start_monitoring</a></h2></rustdoc-topbar><nav class="sidebar"><div class="sidebar-crate"><h2><a href="../../../jellytau_lib/index.html">jellytau_<wbr>lib</a><span class="version">0.11.1</span></h2></div><div class="sidebar-elems"><div id="rustdoc-modnav"><h2><a href="index.html">In jellytau_<wbr>lib::<wbr>commands::<wbr>connectivity</a></h2></div></div></nav><div class="sidebar-resizer" title="Drag to resize sidebar"></div><main><div class="width-limiter"><section id="main-content" class="content" tabindex="-1"><div class="main-heading"><div class="rustdoc-breadcrumbs"><a href="../../index.html">jellytau_lib</a>::<wbr><a href="../index.html">commands</a>::<wbr><a href="index.html">connectivity</a></div><h1>Function <span class="fn">connectivity_<wbr>start_<wbr>monitoring</span>&nbsp;<button id="copy-path" title="Copy item path to clipboard">Copy item path</button></h1><rustdoc-toolbar></rustdoc-toolbar><span class="sub-heading"><a class="src" href="../../../src/jellytau_lib/commands/connectivity.rs.html#47-53">Source</a> </span></div><pre class="rust item-decl"><code>pub async fn connectivity_start_monitoring(
state: State&lt;'_, <a class="struct" href="struct.ConnectivityMonitorWrapper.html" title="struct jellytau_lib::commands::connectivity::ConnectivityMonitorWrapper">ConnectivityMonitorWrapper</a>&gt;,
) -&gt; <a class="enum" href="https://doc.rust-lang.org/1.97.1/core/result/enum.Result.html" title="enum core::result::Result">Result</a>&lt;<a class="primitive" href="https://doc.rust-lang.org/1.97.1/std/primitive.unit.html">()</a>, <a class="struct" href="https://doc.rust-lang.org/1.97.1/alloc/string/struct.String.html" title="struct alloc::string::String">String</a>&gt;</code></pre><details class="toggle top-doc" open><summary class="hideme"><span>Expand description</span></summary><div class="docblock"><p>Start monitoring connectivity with adaptive polling</p>
</div></details></section></div></main></body></html>
@@ -0,0 +1,4 @@
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="Stop monitoring connectivity"><title>connectivity_stop_monitoring in jellytau_lib::commands::connectivity - Rust</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-6b053e98.ttf.woff2,FiraSans-Italic-81dc35de.woff2,FiraSans-Regular-0fe48ade.woff2,FiraSans-MediumItalic-ccf7e434.woff2,FiraSans-Medium-e1aa3f0a.woff2,SourceCodePro-Regular-8badfe75.ttf.woff2,SourceCodePro-Semibold-aa29a496.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2"href="../../../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../../../static.files/normalize-9960930a.css"><link rel="stylesheet" href="../../../static.files/rustdoc-17e0aaed.css"><meta name="rustdoc-vars" data-root-path="../../../" data-static-root-path="../../../static.files/" data-current-crate="jellytau_lib" data-themes="" data-resource-suffix="" data-rustdoc-version="1.97.1 (8bab26f4f 2026-07-14)" data-channel="1.97.1" data-search-js="search-fd9372ac.js" data-stringdex-js="stringdex-2da4960a.js" data-settings-js="settings-170eb4bf.js" ><script src="../../../static.files/storage-41dd4d93.js"></script><script defer src="sidebar-items.js"></script><script defer src="../../../static.files/main-fcd733ba.js"></script><noscript><link rel="stylesheet" href="../../../static.files/noscript-f7c3ffd8.css"></noscript><link rel="alternate icon" type="image/png" href="../../../static.files/favicon-32x32-eab170b8.png"><link rel="icon" type="image/svg+xml" href="../../../static.files/favicon-044be391.svg"></head><body class="rustdoc fn"><a class="skip-main-content" href="#main-content">Skip to main content</a><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><rustdoc-topbar><h2><a href="#">connectivity_stop_monitoring</a></h2></rustdoc-topbar><nav class="sidebar"><div class="sidebar-crate"><h2><a href="../../../jellytau_lib/index.html">jellytau_<wbr>lib</a><span class="version">0.11.1</span></h2></div><div class="sidebar-elems"><div id="rustdoc-modnav"><h2><a href="index.html">In jellytau_<wbr>lib::<wbr>commands::<wbr>connectivity</a></h2></div></div></nav><div class="sidebar-resizer" title="Drag to resize sidebar"></div><main><div class="width-limiter"><section id="main-content" class="content" tabindex="-1"><div class="main-heading"><div class="rustdoc-breadcrumbs"><a href="../../index.html">jellytau_lib</a>::<wbr><a href="../index.html">commands</a>::<wbr><a href="index.html">connectivity</a></div><h1>Function <span class="fn">connectivity_<wbr>stop_<wbr>monitoring</span>&nbsp;<button id="copy-path" title="Copy item path to clipboard">Copy item path</button></h1><rustdoc-toolbar></rustdoc-toolbar><span class="sub-heading"><a class="src" href="../../../src/jellytau_lib/commands/connectivity.rs.html#58-64">Source</a> </span></div><pre class="rust item-decl"><code>pub async fn connectivity_stop_monitoring(
state: State&lt;'_, <a class="struct" href="struct.ConnectivityMonitorWrapper.html" title="struct jellytau_lib::commands::connectivity::ConnectivityMonitorWrapper">ConnectivityMonitorWrapper</a>&gt;,
) -&gt; <a class="enum" href="https://doc.rust-lang.org/1.97.1/core/result/enum.Result.html" title="enum core::result::Result">Result</a>&lt;<a class="primitive" href="https://doc.rust-lang.org/1.97.1/std/primitive.unit.html">()</a>, <a class="struct" href="https://doc.rust-lang.org/1.97.1/alloc/string/struct.String.html" title="struct alloc::string::String">String</a>&gt;</code></pre><details class="toggle top-doc" open><summary class="hideme"><span>Expand description</span></summary><div class="docblock"><p>Stop monitoring connectivity</p>
</div></details></section></div></main></body></html>
@@ -0,0 +1,3 @@
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="Server-reachability / connectivity commands."><title>jellytau_lib::commands::connectivity - Rust</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-6b053e98.ttf.woff2,FiraSans-Italic-81dc35de.woff2,FiraSans-Regular-0fe48ade.woff2,FiraSans-MediumItalic-ccf7e434.woff2,FiraSans-Medium-e1aa3f0a.woff2,SourceCodePro-Regular-8badfe75.ttf.woff2,SourceCodePro-Semibold-aa29a496.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2"href="../../../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../../../static.files/normalize-9960930a.css"><link rel="stylesheet" href="../../../static.files/rustdoc-17e0aaed.css"><meta name="rustdoc-vars" data-root-path="../../../" data-static-root-path="../../../static.files/" data-current-crate="jellytau_lib" data-themes="" data-resource-suffix="" data-rustdoc-version="1.97.1 (8bab26f4f 2026-07-14)" data-channel="1.97.1" data-search-js="search-fd9372ac.js" data-stringdex-js="stringdex-2da4960a.js" data-settings-js="settings-170eb4bf.js" ><script src="../../../static.files/storage-41dd4d93.js"></script><script defer src="../sidebar-items.js"></script><script defer src="../../../static.files/main-fcd733ba.js"></script><noscript><link rel="stylesheet" href="../../../static.files/noscript-f7c3ffd8.css"></noscript><link rel="alternate icon" type="image/png" href="../../../static.files/favicon-32x32-eab170b8.png"><link rel="icon" type="image/svg+xml" href="../../../static.files/favicon-044be391.svg"></head><body class="rustdoc mod"><a class="skip-main-content" href="#main-content">Skip to main content</a><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><rustdoc-topbar><h2><a href="#">Module connectivity</a></h2></rustdoc-topbar><nav class="sidebar"><div class="sidebar-crate"><h2><a href="../../../jellytau_lib/index.html">jellytau_<wbr>lib</a><span class="version">0.11.1</span></h2></div><div class="sidebar-elems"><section id="rustdoc-toc"><h2 class="location"><a href="#">Module connectivity</a></h2><h3><a href="#structs">Module Items</a></h3><ul class="block"><li><a href="#structs" title="Structs">Structs</a></li><li><a href="#functions" title="Functions">Functions</a></li></ul></section><div id="rustdoc-modnav"><h2><a href="../index.html">In jellytau_<wbr>lib::<wbr>commands</a></h2></div></div></nav><div class="sidebar-resizer" title="Drag to resize sidebar"></div><main><div class="width-limiter"><section id="main-content" class="content" tabindex="-1"><div class="main-heading"><div class="rustdoc-breadcrumbs"><a href="../../index.html">jellytau_lib</a>::<wbr><a href="../index.html">commands</a></div><h1>Module <span>connectivity</span>&nbsp;<button id="copy-path" title="Copy item path to clipboard">Copy item path</button></h1><rustdoc-toolbar></rustdoc-toolbar><span class="sub-heading"><a class="src" href="../../../src/jellytau_lib/commands/connectivity.rs.html#1-102">Source</a> </span></div><details class="toggle top-doc" open><summary class="hideme"><span>Expand description</span></summary><div class="docblock"><p>Server-reachability / connectivity commands.</p>
<p>TRACES: UR-043 | IR-027 | DR-055</p>
</div></details><h2 id="structs" class="section-header">Structs<a href="#structs" class="anchor">§</a></h2><dl class="item-table"><dt><a class="struct" href="struct.ConnectivityMonitorWrapper.html" title="struct jellytau_lib::commands::connectivity::ConnectivityMonitorWrapper">Connectivity<wbr>Monitor<wbr>Wrapper</a></dt><dd>Wrapper for ConnectivityMonitor managed state</dd></dl><h2 id="functions" class="section-header">Functions<a href="#functions" class="anchor">§</a></h2><dl class="item-table"><dt><a class="fn" href="fn.connectivity_check_server.html" title="fn jellytau_lib::commands::connectivity::connectivity_check_server">connectivity_<wbr>check_<wbr>server</a></dt><dd>Check if the server is currently reachable</dd><dt><a class="fn" href="fn.connectivity_get_status.html" title="fn jellytau_lib::commands::connectivity::connectivity_get_status">connectivity_<wbr>get_<wbr>status</a></dt><dd>Get the current connectivity status</dd><dt><a class="fn" href="fn.connectivity_mark_reachable.html" title="fn jellytau_lib::commands::connectivity::connectivity_mark_reachable">connectivity_<wbr>mark_<wbr>reachable</a></dt><dd>Mark the server as reachable (called after successful API calls)</dd><dt><a class="fn" href="fn.connectivity_mark_unreachable.html" title="fn jellytau_lib::commands::connectivity::connectivity_mark_unreachable">connectivity_<wbr>mark_<wbr>unreachable</a></dt><dd>Mark the server as unreachable (called after failed API calls)</dd><dt><a class="fn" href="fn.connectivity_set_server_url.html" title="fn jellytau_lib::commands::connectivity::connectivity_set_server_url">connectivity_<wbr>set_<wbr>server_<wbr>url</a></dt><dd>Set the server URL and trigger an immediate check</dd><dt><a class="fn" href="fn.connectivity_start_monitoring.html" title="fn jellytau_lib::commands::connectivity::connectivity_start_monitoring">connectivity_<wbr>start_<wbr>monitoring</a></dt><dd>Start monitoring connectivity with adaptive polling</dd><dt><a class="fn" href="fn.connectivity_stop_monitoring.html" title="fn jellytau_lib::commands::connectivity::connectivity_stop_monitoring">connectivity_<wbr>stop_<wbr>monitoring</a></dt><dd>Stop monitoring connectivity</dd></dl></section></div></main></body></html>
@@ -0,0 +1 @@
window.SIDEBAR_ITEMS = {"fn":["connectivity_check_server","connectivity_get_status","connectivity_mark_reachable","connectivity_mark_unreachable","connectivity_set_server_url","connectivity_start_monitoring","connectivity_stop_monitoring"],"struct":["ConnectivityMonitorWrapper"]};
File diff suppressed because one or more lines are too long
@@ -0,0 +1,9 @@
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="Calculate progress percentage from position and duration"><title>calc_progress in jellytau_lib::commands::conversions - Rust</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-6b053e98.ttf.woff2,FiraSans-Italic-81dc35de.woff2,FiraSans-Regular-0fe48ade.woff2,FiraSans-MediumItalic-ccf7e434.woff2,FiraSans-Medium-e1aa3f0a.woff2,SourceCodePro-Regular-8badfe75.ttf.woff2,SourceCodePro-Semibold-aa29a496.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2"href="../../../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../../../static.files/normalize-9960930a.css"><link rel="stylesheet" href="../../../static.files/rustdoc-17e0aaed.css"><meta name="rustdoc-vars" data-root-path="../../../" data-static-root-path="../../../static.files/" data-current-crate="jellytau_lib" data-themes="" data-resource-suffix="" data-rustdoc-version="1.97.1 (8bab26f4f 2026-07-14)" data-channel="1.97.1" data-search-js="search-fd9372ac.js" data-stringdex-js="stringdex-2da4960a.js" data-settings-js="settings-170eb4bf.js" ><script src="../../../static.files/storage-41dd4d93.js"></script><script defer src="sidebar-items.js"></script><script defer src="../../../static.files/main-fcd733ba.js"></script><noscript><link rel="stylesheet" href="../../../static.files/noscript-f7c3ffd8.css"></noscript><link rel="alternate icon" type="image/png" href="../../../static.files/favicon-32x32-eab170b8.png"><link rel="icon" type="image/svg+xml" href="../../../static.files/favicon-044be391.svg"></head><body class="rustdoc fn"><a class="skip-main-content" href="#main-content">Skip to main content</a><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><rustdoc-topbar><h2><a href="#">calc_progress</a></h2></rustdoc-topbar><nav class="sidebar"><div class="sidebar-crate"><h2><a href="../../../jellytau_lib/index.html">jellytau_<wbr>lib</a><span class="version">0.11.1</span></h2></div><div class="sidebar-elems"><section id="rustdoc-toc"><h2 class="location"><a href="#">calc_<wbr>progress</a></h2><h3><a href="#">Sections</a></h3><ul class="block top-toc"><li><a href="#arguments" title="Arguments">Arguments</a></li><li><a href="#returns" title="Returns">Returns</a></li></ul></section><div id="rustdoc-modnav"><h2><a href="index.html">In jellytau_<wbr>lib::<wbr>commands::<wbr>conversions</a></h2></div></div></nav><div class="sidebar-resizer" title="Drag to resize sidebar"></div><main><div class="width-limiter"><section id="main-content" class="content" tabindex="-1"><div class="main-heading"><div class="rustdoc-breadcrumbs"><a href="../../index.html">jellytau_lib</a>::<wbr><a href="../index.html">commands</a>::<wbr><a href="index.html">conversions</a></div><h1>Function <span class="fn">calc_<wbr>progress</span>&nbsp;<button id="copy-path" title="Copy item path to clipboard">Copy item path</button></h1><rustdoc-toolbar></rustdoc-toolbar><span class="sub-heading"><a class="src" href="../../../src/jellytau_lib/commands/conversions.rs.html#65-67">Source</a> </span></div><pre class="rust item-decl"><code>pub fn calc_progress(position: <a class="primitive" href="https://doc.rust-lang.org/1.97.1/std/primitive.f64.html">f64</a>, duration: <a class="primitive" href="https://doc.rust-lang.org/1.97.1/std/primitive.f64.html">f64</a>) -&gt; <a class="primitive" href="https://doc.rust-lang.org/1.97.1/std/primitive.f64.html">f64</a></code></pre><details class="toggle top-doc" open><summary class="hideme"><span>Expand description</span></summary><div class="docblock"><p>Calculate progress percentage from position and duration</p>
<h2 id="arguments"><a class="doc-anchor" href="#arguments">§</a>Arguments</h2>
<ul>
<li><code>position</code> - Current position in seconds</li>
<li><code>duration</code> - Total duration in seconds</li>
</ul>
<h2 id="returns"><a class="doc-anchor" href="#returns">§</a>Returns</h2>
<p>Progress as percentage (0.0 to 100.0)</p>
</div></details></section></div></main></body></html>
@@ -0,0 +1,8 @@
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="Convert percentage volume (0-100) to normalized (0.0-1.0)"><title>convert_percent_to_volume in jellytau_lib::commands::conversions - Rust</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-6b053e98.ttf.woff2,FiraSans-Italic-81dc35de.woff2,FiraSans-Regular-0fe48ade.woff2,FiraSans-MediumItalic-ccf7e434.woff2,FiraSans-Medium-e1aa3f0a.woff2,SourceCodePro-Regular-8badfe75.ttf.woff2,SourceCodePro-Semibold-aa29a496.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2"href="../../../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../../../static.files/normalize-9960930a.css"><link rel="stylesheet" href="../../../static.files/rustdoc-17e0aaed.css"><meta name="rustdoc-vars" data-root-path="../../../" data-static-root-path="../../../static.files/" data-current-crate="jellytau_lib" data-themes="" data-resource-suffix="" data-rustdoc-version="1.97.1 (8bab26f4f 2026-07-14)" data-channel="1.97.1" data-search-js="search-fd9372ac.js" data-stringdex-js="stringdex-2da4960a.js" data-settings-js="settings-170eb4bf.js" ><script src="../../../static.files/storage-41dd4d93.js"></script><script defer src="sidebar-items.js"></script><script defer src="../../../static.files/main-fcd733ba.js"></script><noscript><link rel="stylesheet" href="../../../static.files/noscript-f7c3ffd8.css"></noscript><link rel="alternate icon" type="image/png" href="../../../static.files/favicon-32x32-eab170b8.png"><link rel="icon" type="image/svg+xml" href="../../../static.files/favicon-044be391.svg"></head><body class="rustdoc fn"><a class="skip-main-content" href="#main-content">Skip to main content</a><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><rustdoc-topbar><h2><a href="#">convert_percent_to_volume</a></h2></rustdoc-topbar><nav class="sidebar"><div class="sidebar-crate"><h2><a href="../../../jellytau_lib/index.html">jellytau_<wbr>lib</a><span class="version">0.11.1</span></h2></div><div class="sidebar-elems"><section id="rustdoc-toc"><h2 class="location"><a href="#">convert_<wbr>percent_<wbr>to_<wbr>volume</a></h2><h3><a href="#">Sections</a></h3><ul class="block top-toc"><li><a href="#arguments" title="Arguments">Arguments</a></li><li><a href="#returns" title="Returns">Returns</a></li></ul></section><div id="rustdoc-modnav"><h2><a href="index.html">In jellytau_<wbr>lib::<wbr>commands::<wbr>conversions</a></h2></div></div></nav><div class="sidebar-resizer" title="Drag to resize sidebar"></div><main><div class="width-limiter"><section id="main-content" class="content" tabindex="-1"><div class="main-heading"><div class="rustdoc-breadcrumbs"><a href="../../index.html">jellytau_lib</a>::<wbr><a href="../index.html">commands</a>::<wbr><a href="index.html">conversions</a></div><h1>Function <span class="fn">convert_<wbr>percent_<wbr>to_<wbr>volume</span>&nbsp;<button id="copy-path" title="Copy item path to clipboard">Copy item path</button></h1><rustdoc-toolbar></rustdoc-toolbar><span class="sub-heading"><a class="src" href="../../../src/jellytau_lib/commands/conversions.rs.html#78-80">Source</a> </span></div><pre class="rust item-decl"><code>pub fn convert_percent_to_volume(percent: <a class="primitive" href="https://doc.rust-lang.org/1.97.1/std/primitive.f64.html">f64</a>) -&gt; <a class="primitive" href="https://doc.rust-lang.org/1.97.1/std/primitive.f64.html">f64</a></code></pre><details class="toggle top-doc" open><summary class="hideme"><span>Expand description</span></summary><div class="docblock"><p>Convert percentage volume (0-100) to normalized (0.0-1.0)</p>
<h2 id="arguments"><a class="doc-anchor" href="#arguments">§</a>Arguments</h2>
<ul>
<li><code>percent</code> - Volume as percentage (0 to 100)</li>
</ul>
<h2 id="returns"><a class="doc-anchor" href="#returns">§</a>Returns</h2>
<p>Normalized volume (0.0 to 1.0)</p>
</div></details></section></div></main></body></html>
@@ -0,0 +1,8 @@
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="Convert Jellyfin ticks to seconds"><title>convert_ticks_to_seconds in jellytau_lib::commands::conversions - Rust</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-6b053e98.ttf.woff2,FiraSans-Italic-81dc35de.woff2,FiraSans-Regular-0fe48ade.woff2,FiraSans-MediumItalic-ccf7e434.woff2,FiraSans-Medium-e1aa3f0a.woff2,SourceCodePro-Regular-8badfe75.ttf.woff2,SourceCodePro-Semibold-aa29a496.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2"href="../../../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../../../static.files/normalize-9960930a.css"><link rel="stylesheet" href="../../../static.files/rustdoc-17e0aaed.css"><meta name="rustdoc-vars" data-root-path="../../../" data-static-root-path="../../../static.files/" data-current-crate="jellytau_lib" data-themes="" data-resource-suffix="" data-rustdoc-version="1.97.1 (8bab26f4f 2026-07-14)" data-channel="1.97.1" data-search-js="search-fd9372ac.js" data-stringdex-js="stringdex-2da4960a.js" data-settings-js="settings-170eb4bf.js" ><script src="../../../static.files/storage-41dd4d93.js"></script><script defer src="sidebar-items.js"></script><script defer src="../../../static.files/main-fcd733ba.js"></script><noscript><link rel="stylesheet" href="../../../static.files/noscript-f7c3ffd8.css"></noscript><link rel="alternate icon" type="image/png" href="../../../static.files/favicon-32x32-eab170b8.png"><link rel="icon" type="image/svg+xml" href="../../../static.files/favicon-044be391.svg"></head><body class="rustdoc fn"><a class="skip-main-content" href="#main-content">Skip to main content</a><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><rustdoc-topbar><h2><a href="#">convert_ticks_to_seconds</a></h2></rustdoc-topbar><nav class="sidebar"><div class="sidebar-crate"><h2><a href="../../../jellytau_lib/index.html">jellytau_<wbr>lib</a><span class="version">0.11.1</span></h2></div><div class="sidebar-elems"><section id="rustdoc-toc"><h2 class="location"><a href="#">convert_<wbr>ticks_<wbr>to_<wbr>seconds</a></h2><h3><a href="#">Sections</a></h3><ul class="block top-toc"><li><a href="#arguments" title="Arguments">Arguments</a></li><li><a href="#returns" title="Returns">Returns</a></li></ul></section><div id="rustdoc-modnav"><h2><a href="index.html">In jellytau_<wbr>lib::<wbr>commands::<wbr>conversions</a></h2></div></div></nav><div class="sidebar-resizer" title="Drag to resize sidebar"></div><main><div class="width-limiter"><section id="main-content" class="content" tabindex="-1"><div class="main-heading"><div class="rustdoc-breadcrumbs"><a href="../../index.html">jellytau_lib</a>::<wbr><a href="../index.html">commands</a>::<wbr><a href="index.html">conversions</a></div><h1>Function <span class="fn">convert_<wbr>ticks_<wbr>to_<wbr>seconds</span>&nbsp;<button id="copy-path" title="Copy item path to clipboard">Copy item path</button></h1><rustdoc-toolbar></rustdoc-toolbar><span class="sub-heading"><a class="src" href="../../../src/jellytau_lib/commands/conversions.rs.html#51-53">Source</a> </span></div><pre class="rust item-decl"><code>pub fn convert_ticks_to_seconds(ticks: <a class="primitive" href="https://doc.rust-lang.org/1.97.1/std/primitive.i64.html">i64</a>) -&gt; <a class="primitive" href="https://doc.rust-lang.org/1.97.1/std/primitive.f64.html">f64</a></code></pre><details class="toggle top-doc" open><summary class="hideme"><span>Expand description</span></summary><div class="docblock"><p>Convert Jellyfin ticks to seconds</p>
<h2 id="arguments"><a class="doc-anchor" href="#arguments">§</a>Arguments</h2>
<ul>
<li><code>ticks</code> - Time in Jellyfin ticks (10,000,000 ticks = 1 second)</li>
</ul>
<h2 id="returns"><a class="doc-anchor" href="#returns">§</a>Returns</h2>
<p>Time in seconds</p>
</div></details></section></div></main></body></html>
@@ -0,0 +1,8 @@
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="Format time in seconds to MM:SS display string"><title>format_time_seconds in jellytau_lib::commands::conversions - Rust</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-6b053e98.ttf.woff2,FiraSans-Italic-81dc35de.woff2,FiraSans-Regular-0fe48ade.woff2,FiraSans-MediumItalic-ccf7e434.woff2,FiraSans-Medium-e1aa3f0a.woff2,SourceCodePro-Regular-8badfe75.ttf.woff2,SourceCodePro-Semibold-aa29a496.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2"href="../../../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../../../static.files/normalize-9960930a.css"><link rel="stylesheet" href="../../../static.files/rustdoc-17e0aaed.css"><meta name="rustdoc-vars" data-root-path="../../../" data-static-root-path="../../../static.files/" data-current-crate="jellytau_lib" data-themes="" data-resource-suffix="" data-rustdoc-version="1.97.1 (8bab26f4f 2026-07-14)" data-channel="1.97.1" data-search-js="search-fd9372ac.js" data-stringdex-js="stringdex-2da4960a.js" data-settings-js="settings-170eb4bf.js" ><script src="../../../static.files/storage-41dd4d93.js"></script><script defer src="sidebar-items.js"></script><script defer src="../../../static.files/main-fcd733ba.js"></script><noscript><link rel="stylesheet" href="../../../static.files/noscript-f7c3ffd8.css"></noscript><link rel="alternate icon" type="image/png" href="../../../static.files/favicon-32x32-eab170b8.png"><link rel="icon" type="image/svg+xml" href="../../../static.files/favicon-044be391.svg"></head><body class="rustdoc fn"><a class="skip-main-content" href="#main-content">Skip to main content</a><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><rustdoc-topbar><h2><a href="#">format_time_seconds</a></h2></rustdoc-topbar><nav class="sidebar"><div class="sidebar-crate"><h2><a href="../../../jellytau_lib/index.html">jellytau_<wbr>lib</a><span class="version">0.11.1</span></h2></div><div class="sidebar-elems"><section id="rustdoc-toc"><h2 class="location"><a href="#">format_<wbr>time_<wbr>seconds</a></h2><h3><a href="#">Sections</a></h3><ul class="block top-toc"><li><a href="#arguments" title="Arguments">Arguments</a></li><li><a href="#returns" title="Returns">Returns</a></li></ul></section><div id="rustdoc-modnav"><h2><a href="index.html">In jellytau_<wbr>lib::<wbr>commands::<wbr>conversions</a></h2></div></div></nav><div class="sidebar-resizer" title="Drag to resize sidebar"></div><main><div class="width-limiter"><section id="main-content" class="content" tabindex="-1"><div class="main-heading"><div class="rustdoc-breadcrumbs"><a href="../../index.html">jellytau_lib</a>::<wbr><a href="../index.html">commands</a>::<wbr><a href="index.html">conversions</a></div><h1>Function <span class="fn">format_<wbr>time_<wbr>seconds</span>&nbsp;<button id="copy-path" title="Copy item path to clipboard">Copy item path</button></h1><rustdoc-toolbar></rustdoc-toolbar><span class="sub-heading"><a class="src" href="../../../src/jellytau_lib/commands/conversions.rs.html#21-23">Source</a> </span></div><pre class="rust item-decl"><code>pub fn format_time_seconds(seconds: <a class="primitive" href="https://doc.rust-lang.org/1.97.1/std/primitive.f64.html">f64</a>) -&gt; <a class="struct" href="https://doc.rust-lang.org/1.97.1/alloc/string/struct.String.html" title="struct alloc::string::String">String</a></code></pre><details class="toggle top-doc" open><summary class="hideme"><span>Expand description</span></summary><div class="docblock"><p>Format time in seconds to MM:SS display string</p>
<h2 id="arguments"><a class="doc-anchor" href="#arguments">§</a>Arguments</h2>
<ul>
<li><code>seconds</code> - Time in seconds</li>
</ul>
<h2 id="returns"><a class="doc-anchor" href="#returns">§</a>Returns</h2>
<p>Formatted string like “3:45” or “12:09”</p>
</div></details></section></div></main></body></html>
@@ -0,0 +1,13 @@
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta name="generator" content="rustdoc"><meta name="description" content="Format time in seconds to HH:MM:SS or MM:SS display string"><title>format_time_seconds_long in jellytau_lib::commands::conversions - Rust</title><script>if(window.location.protocol!=="file:")document.head.insertAdjacentHTML("beforeend","SourceSerif4-Regular-6b053e98.ttf.woff2,FiraSans-Italic-81dc35de.woff2,FiraSans-Regular-0fe48ade.woff2,FiraSans-MediumItalic-ccf7e434.woff2,FiraSans-Medium-e1aa3f0a.woff2,SourceCodePro-Regular-8badfe75.ttf.woff2,SourceCodePro-Semibold-aa29a496.ttf.woff2".split(",").map(f=>`<link rel="preload" as="font" type="font/woff2"href="../../../static.files/${f}">`).join(""))</script><link rel="stylesheet" href="../../../static.files/normalize-9960930a.css"><link rel="stylesheet" href="../../../static.files/rustdoc-17e0aaed.css"><meta name="rustdoc-vars" data-root-path="../../../" data-static-root-path="../../../static.files/" data-current-crate="jellytau_lib" data-themes="" data-resource-suffix="" data-rustdoc-version="1.97.1 (8bab26f4f 2026-07-14)" data-channel="1.97.1" data-search-js="search-fd9372ac.js" data-stringdex-js="stringdex-2da4960a.js" data-settings-js="settings-170eb4bf.js" ><script src="../../../static.files/storage-41dd4d93.js"></script><script defer src="sidebar-items.js"></script><script defer src="../../../static.files/main-fcd733ba.js"></script><noscript><link rel="stylesheet" href="../../../static.files/noscript-f7c3ffd8.css"></noscript><link rel="alternate icon" type="image/png" href="../../../static.files/favicon-32x32-eab170b8.png"><link rel="icon" type="image/svg+xml" href="../../../static.files/favicon-044be391.svg"></head><body class="rustdoc fn"><a class="skip-main-content" href="#main-content">Skip to main content</a><!--[if lte IE 11]><div class="warning">This old browser is unsupported and will most likely display funky things.</div><![endif]--><rustdoc-topbar><h2><a href="#">format_time_seconds_long</a></h2></rustdoc-topbar><nav class="sidebar"><div class="sidebar-crate"><h2><a href="../../../jellytau_lib/index.html">jellytau_<wbr>lib</a><span class="version">0.11.1</span></h2></div><div class="sidebar-elems"><section id="rustdoc-toc"><h2 class="location"><a href="#">format_<wbr>time_<wbr>seconds_<wbr>long</a></h2><h3><a href="#">Sections</a></h3><ul class="block top-toc"><li><a href="#arguments" title="Arguments">Arguments</a></li><li><a href="#returns" title="Returns">Returns</a></li></ul></section><div id="rustdoc-modnav"><h2><a href="index.html">In jellytau_<wbr>lib::<wbr>commands::<wbr>conversions</a></h2></div></div></nav><div class="sidebar-resizer" title="Drag to resize sidebar"></div><main><div class="width-limiter"><section id="main-content" class="content" tabindex="-1"><div class="main-heading"><div class="rustdoc-breadcrumbs"><a href="../../index.html">jellytau_lib</a>::<wbr><a href="../index.html">commands</a>::<wbr><a href="index.html">conversions</a></div><h1>Function <span class="fn">format_<wbr>time_<wbr>seconds_<wbr>long</span>&nbsp;<button id="copy-path" title="Copy item path to clipboard">Copy item path</button></h1><rustdoc-toolbar></rustdoc-toolbar><span class="sub-heading"><a class="src" href="../../../src/jellytau_lib/commands/conversions.rs.html#38-40">Source</a> </span></div><pre class="rust item-decl"><code>pub fn format_time_seconds_long(seconds: <a class="primitive" href="https://doc.rust-lang.org/1.97.1/std/primitive.f64.html">f64</a>) -&gt; <a class="struct" href="https://doc.rust-lang.org/1.97.1/alloc/string/struct.String.html" title="struct alloc::string::String">String</a></code></pre><details class="toggle top-doc" open><summary class="hideme"><span>Expand description</span></summary><div class="docblock"><p>Format time in seconds to HH:MM:SS or MM:SS display string</p>
<p>Automatically chooses format based on duration:</p>
<ul>
<li>Less than 1 hour: Returns MM:SS format</li>
<li>1 hour or more: Returns HH:MM:SS format</li>
</ul>
<h2 id="arguments"><a class="doc-anchor" href="#arguments">§</a>Arguments</h2>
<ul>
<li><code>seconds</code> - Time in seconds</li>
</ul>
<h2 id="returns"><a class="doc-anchor" href="#returns">§</a>Returns</h2>
<p>Formatted string like “1:23:45” or “3:45”</p>
</div></details></section></div></main></body></html>

Some files were not shown because too many files have changed in this diff Show More