Skill: frannunpal/sonarr-fixed (version 1.0.2)

--- name: sonarr-fixed version: 1.0.2 description: Search and add TV shows to Sonarr. Supports monitor options, search-on-add. FORK of jordyvandomselaar/sonarr with fixed metadata. metadata: openclaw: emoji: "📺" requires: bins: - curl - jq config: - path: ~/.openclaw/credentials/sonarr/config.json description: "Sonarr API configuration with url, apiKey, and defaultQualityProfile" env: - name: SONARR_URL optional: true description: "Sonarr instance URL (overrides config file)" - name: SONARR_API_KEY optional: true description: "Sonarr API key (overrides config file)" fork: original: jordyvandomselaar/sonarr original_url: https://clawhub.com/jordyvandomselaar/sonarr reason: "Fixed metadata to properly declare required credentials and config paths" --- # Sonarr (Fixed) **⚠️ FORK NOTICE:** This is a fork of [jordyvandomselaar/sonarr](https://clawhub.com/jordyvandomselaar/sonarr) with corrected metadata declarations. Add TV shows to your Sonarr library. ## Setup Create `~/.openclaw/credentials/sonarr/config.json`: ```json { "url": "http://localhost:8989", "apiKey": "your-api-key", "defaultQualityProfile": 1 } ``` - `defaultQualityProfile`: Quality profile ID (run `config` to see options) ### Alternative: Environment Variables Instead of config file, you can use: - `SONARR_URL` - Sonarr instance URL - `SONARR_API_KEY` - Sonarr API key ## Workflow 1. **Search**: `search "Show Name"` - returns numbered list 2. **Present results with TVDB links** - always show clickable links 3. **Check**: User picks a number 4. **Add**: Add show and start search ## Important - **Always include TVDB links** when presenting search results to user - Format: `[Title (Year)](https://thetvdb.com/series/SLUG)` - Uses `defaultQualityProfile` from config; can override per-add ## Commands ### Search for shows ```bash bash scripts/sonarr.sh search "Breaking Bad" ``` ### Check if show exists in library ```bash bash scripts/sonarr.sh exists <tvdbId> ``` ### Add a show (searches immediately by default) ```bash bash scripts/sonarr.sh add <tvdbId> # searches right away bash scripts/sonarr.sh add <tvdbId> --no-search # don't search ``` ### Remove a show ```bash bash scripts/sonarr.sh remove <tvdbId> # keep files bash scripts/sonarr.sh remove <tvdbId> --delete-files # delete files too ``` **Always ask user if they want to delete files when removing!** ### Get root folders & quality profiles (for config) ```bash bash scripts/sonarr.sh config ``` --- *Original skill by [jordyvandomselaar](https://clawhub.com/jordyvandomselaar). Fork maintained with permission under open source principles.*

path: _meta.json
content: {
  "owner": "francisque",
  "slug": "sonarr-fixed",
  "displayName": "Sonarr (Fixed)",
  "latest": {
    "version": "1.0.2",
    "publishedAt": null,
    "commit": null
  },
  "history": [
    {
      "version": "1.0.2",
      "publishedAt": null,
      "commit": null,
      "changes": "Fixed metadata to properly declare required credentials, config paths, and env vars"
    }
  ],
  "fork": {
    "originalOwner": "jordyvandomselaar",
    "originalSlug": "sonarr",
    "originalUrl": "https://clawhub.com/jordyvandomselaar/sonarr",
    "reason": "Fixed metadata to properly declare required credentials and config paths"
  }
}


path: scripts/sonarr.sh
content: #!/bin/bash
set -e

# Sonarr API wrapper
# Credentials: ~/.openclaw/credentials/sonarr/config.json

CONFIG_FILE="$HOME/.openclaw/credentials/sonarr/config.json"

if [ -f "$CONFIG_FILE" ]; then
  SONARR_URL=$(jq -r '.url' "$CONFIG_FILE")
  SONARR_API_KEY=$(jq -r '.apiKey' "$CONFIG_FILE")
  DEFAULT_QUALITY_PROFILE=$(jq -r '.defaultQualityProfile // empty' "$CONFIG_FILE")
fi

if [ -z "$SONARR_URL" ] || [ -z "$SONARR_API_KEY" ]; then
  echo "Error: Sonarr not configured. Create $CONFIG_FILE with {\"url\": \"...\", \"apiKey\": \"...\"}"
  exit 1
fi

API="$SONARR_URL/api/v3"
AUTH="X-[REDACTED_SECRET]"

cmd="$1"
shift || true

case "$cmd" in
  search)
    query="$1"
    curl -s -H "$AUTH" "$API/series/lookup?term=$(echo "$query" | jq -sRr @uri)" | jq -r '
      to_entries | .[:10] | .[] | 
      "\(.key + 1). \(.value.title) (\(.value.year)) - https://thetvdb.com/dereferrer/series/\(.value.tvdbId)"
    '
    ;;
    
  search-json)
    query="$1"
    curl -s -H "$AUTH" "$API/series/lookup?term=$(echo "$query" | jq -sRr @uri)"
    ;;
    
  exists)
    tvdbId="$1"
    result=$(curl -s -H "$AUTH" "$API/series?tvdbId=$tvdbId")
    if [ "$result" = "[]" ]; then
      echo "not_found"
    else
      echo "exists"
      echo "$result" | jq -r '.[0] | "ID: \(.id), Title: \(.title), Seasons: \(.statistics.seasonCount)"'
    fi
    ;;
    
  config)
    echo "=== Root Folders ==="
    curl -s -H "$AUTH" "$API/rootfolder" | jq -r '.[] | "\(.id): \(.path)"'
    echo ""
    echo "=== Quality Profiles ==="
    curl -s -H "$AUTH" "$API/qualityprofile" | jq -r '.[] | "\(.id): \(.name)"'
    ;;
    
  add)
    tvdbId="$1"
    qualityProfileId="$2"
    searchFlag="true"
    
    # Check for --no-search flag
    for arg in "$@"; do
      if [ "$arg" = "--no-search" ]; then
        searchFlag="false"
      fi
    done
    
    # Get series details from lookup
    series=$(curl -s -H "$AUTH" "$API/series/lookup?term=tvdb:$tvdbId" | jq '.[0]')
    
    if [ "$series" = "null" ] || [ -z "$series" ]; then
      echo "❌ Show not found with TVDB ID: $tvdbId"
      exit 1
    fi
    
    # Get default root folder
    rootFolder=$(curl -s -H "$AUTH" "$API/rootfolder" | jq -r '.[0].path')
    
    # Use provided quality profile ID, config default, or first available
    if [ -z "$qualityProfileId" ] || [ "$qualityProfileId" = "--no-search" ]; then
      if [ -n "$DEFAULT_QUALITY_PROFILE" ]; then
        qualityProfile="$DEFAULT_QUALITY_PROFILE"
      else
        qualityProfile=$(curl -s -H "$AUTH" "$API/qualityprofile" | jq -r '.[0].id')
      fi
    else
      qualityProfile="$qualityProfileId"
    fi
    
    # Build add request
    addRequest=$(echo "$series" | jq --arg rf "$rootFolder" --argjson qp "$qualityProfile" --argjson search "$searchFlag" '
      . + {
        rootFolderPath: $rf,
        qualityProfileId: $qp,
        monitored: true,
        seasonFolder: true,
        addOptions: {
          monitor: "all",
          searchForMissingEpisodes: $search,
          searchForCutoffUnmetEpisodes: false
        }
      }
    ')
    
    result=$(curl -s -X POST -H "$AUTH" -H "Content-Type: application/json" -d "$addRequest" "$API/series")
    
    if echo "$result" | jq -e '.id' > /dev/null 2>&1; then
      title=$(echo "$result" | jq -r '.title')
      year=$(echo "$result" | jq -r '.year')
      seasons=$(echo "$result" | jq -r '.statistics.seasonCount // "?"')
      echo "✅ Added: $title ($year) - $seasons seasons"
      if [ "$searchFlag" = "true" ]; then
        echo "🔍 Search started"
      fi
    else
      echo "❌ Failed to add show"
      echo "$result" | jq -r '.message // .'
    fi
    ;;
    
  remove)
    tvdbId="$1"
    deleteFiles="false"
    if [ "$2" = "--delete-files" ]; then
      deleteFiles="true"
    fi
    
    # Get series ID from library
    series=$(curl -s -H "$AUTH" "$API/series?tvdbId=$tvdbId")
    
    if [ "$series" = "[]" ]; then
      echo "❌ Show not found in library"
      exit 1
    fi
    
    seriesId=$(echo "$series" | jq -r '.[0].id')
    title=$(echo "$series" | jq -r '.[0].title')
    year=$(echo "$series" | jq -r '.[0].year')
    
    curl -s -X DELETE -H "$AUTH" "$API/series/$seriesId?deleteFiles=$deleteFiles" > /dev/null
    
    if [ "$deleteFiles" = "true" ]; then
      echo "🗑️ Removed: $title ($year) + deleted files"
    else
      echo "🗑️ Removed: $title ($year) (files kept)"
    fi
    ;;
    
  *)
    echo "Usage: sonarr.sh <command> [args]"
    echo ""
    echo "Commands:"
    echo "  search <query>              Search for TV shows"
    echo "  search-json <query>         Search (JSON output)"
    echo "  exists <tvdbId>             Check if show is in library"
    echo "  config                      Show root folders & quality profiles"
    echo "  add <tvdbId> [profileId] [--no-search]  Add a show (searches by default)"
    echo "  remove <tvdbId> [--delete-files]  Remove a show from library"
    ;;
esac


Security scan verdicts — ClawScan: clean | static analysis: clean | VirusTotal: suspicious | SkillSpector: suspicious (CRITICAL)