### Redirecterr Sample Config: Multiple Instances and Filters Source: https://github.com/varthe/redirecterr/blob/main/README.md A comprehensive sample configuration demonstrating the setup of multiple Sonarr instances (including a 4K and an anime instance) and filters to route TV requests based on media type and keywords. ```yaml overseerr_url: "" overseerr_api_token: "" approve_on_no_match: true instances: sonarr: server_id: 0 root_folder: "/mnt/plex/Shows" sonarr_4k: server_id: 1 root_folder: "/mnt/plex/Shows - 4K" sonarr_anime: server_id: 2 root_folder: "/mnt/plex/Anime" filters: # Send anime to sonarr_anime - media_type: tv conditions: keywords: anime apply: sonarr_anime # Send everything else to sonarr and sonarr_4k instances - media_type: tv apply: ["sonarr", "sonarr_4k"] ``` -------------------------------- ### Redirecterr Config: Filter Example Source: https://github.com/varthe/redirecterr/blob/main/README.md Example of a filter configuration that routes movie requests containing 'anime' or 'animation' keywords to the 'radarr_anime' instance, while excluding content ratings 12 and 16, and specifically targeting requests by the username 'user'. ```yaml filters: - media_type: movie # is_4k: true # Optional conditions: keywords: include: ["anime", "animation"] contentRatings: exclude: [12, 16] requestedBy_username: user max_seasons: 2 apply: radarr_anime ``` -------------------------------- ### Overseerr Webhook JSON Payload Example Source: https://github.com/varthe/redirecterr/blob/main/README.md Configure this JSON payload in Overseerr's webhook settings to send relevant request details to Redirecterr. This payload structure is used for processing notification types like 'Request Pending Approval'. ```json { "notification_type": "{{notification_type}}", "media": { "media_type": "{{media_type}}", "tmdbId": "{{media_tmdbid}}", "status": "{{media_status}}", "status4k": "{{media_status4k}}" }, "request": { "request_id": "{{request_id}}", "requestedBy_email": "{{requestedBy_email}}", "requestedBy_username": "{{requestedBy_username}}" }, "{{extra}}": [] } ``` -------------------------------- ### Docker Compose Configuration for Redirecterr Source: https://github.com/varthe/redirecterr/blob/main/README.md Use this Docker Compose configuration to set up and run the Redirecterr service. Ensure to map your configuration file and logs directory. ```yaml services: redirecterr: image: varthe/redirecterr:latest container_name: redirecterr hostname: redirecterr ports: - 8481:8481 volumes: - /path/to/config.yaml:/config/config.yaml - /path/to/logs:/logs environment: - LOG_LEVEL=info ``` -------------------------------- ### `sendToInstances` — Instance Dispatcher Source: https://context7.com/varthe/redirecterr/llms.txt Applies instance-specific configuration (root folder, server ID, optional quality profile) to an Overseerr request via PUT, then approves it via POST. It iterates over multiple instances if the matched filter specifies an array in `apply`. Individual instance failures are logged as warnings without aborting the remaining instances. ```APIDOC ## `sendToInstances` — Instance Dispatcher Applies instance-specific configuration (root folder, server ID, optional quality profile) to an Overseerr request via PUT, then approves it via POST. Iterates over multiple instances if the matched filter specifies an array in `apply`. Individual instance failures are logged as warnings without aborting the remaining instances. ```typescript import { sendToInstances } from "./src/services/instance" // config.instances must contain entries matching these names // Internally called by handleWebhook after findInstances succeeds // Single instance await sendToInstances("sonarr_anime", "42", { mediaType: "tv", seasons: [1, 2] }) // → PUT /api/v1/request/42 { mediaType: "tv", seasons: [1,2], rootFolder: "/mnt/Anime", serverId: 2 } // → POST /api/v1/request/42/approve // Multiple instances await sendToInstances(["sonarr", "sonarr_4k"], "43", { mediaType: "tv", seasons: [1] }) // → Applies config + approves on "sonarr" // → Applies config + approves on "sonarr_4k" // Instance with approve: false skips the approval step // Instance not found in config.instances → logged as warning, skipped ``` ``` -------------------------------- ### Redirecterr Config: Instance Definition Source: https://github.com/varthe/redirecterr/blob/main/README.md Define your Radarr or Sonarr instances, specifying the server ID as it appears in Overseerr, the root folder for media, and optionally the quality profile ID and approval behavior. ```yaml instances: radarr: server_id: 0 # Match the order in Overseerr > Settings > Services (example below) root_folder: /mnt/movies # quality_profile_id: 1 # Optional # approve: false # Optional (default is true) ``` -------------------------------- ### Configuration File - config.yaml Source: https://context7.com/varthe/redirecterr/llms.txt Defines Overseerr credentials, Radarr/Sonarr instance mappings, and ordered filter rules. This file is validated at startup against a JSON Schema. ```yaml # config.yaml — full example overseerr_url: "http://overseerr:5055" overseerr_api_token: "your-api-token-here" # Auto-approve requests that match no filter (default: false if omitted) approve_on_no_match: true instances: # Name keys are referenced in filter `apply` fields radarr: server_id: 0 # Position in Overseerr > Settings > Services (0-indexed, left-to-right) root_folder: "/mnt/media/Movies" quality_profile_id: 4 # Optional: overrides Overseerr default. GET /api/v3/qualityProfile?apiKey=... approve: true # Optional: set false to skip auto-approval for this instance radarr_anime: server_id: 1 root_folder: "/mnt/media/Anime Movies" sonarr: server_id: 0 root_folder: "/mnt/media/Shows" sonarr_4k: server_id: 1 root_folder: "/mnt/media/Shows - 4K" sonarr_anime: server_id: 2 root_folder: "/mnt/media/Anime" filters: # Filters are evaluated top-to-bottom; the FIRST match wins # Route anime TV shows to sonarr_anime - media_type: tv conditions: keywords: include: ["anime", "animation"] apply: sonarr_anime # Route 4K-only TV requests to sonarr_4k - media_type: tv is_4k: true apply: sonarr_4k # Route all remaining TV to sonarr - media_type: tv apply: sonarr # Route anime movies (exclude horror) - media_type: movie conditions: keywords: include: ["anime", "animation"] exclude: ["horror"] apply: radarr_anime # Route all remaining movies to radarr - media_type: movie apply: radarr ``` -------------------------------- ### findInstances Source: https://context7.com/varthe/redirecterr/llms.txt Evaluates an ordered list of filters against a webhook payload and its associated TMDB/Overseerr media metadata. Returns the `apply` target (instance name or array of names) for the first matching filter, or `null` if nothing matches. Filters are matched on `media_type`, optional `is_4k`, and an arbitrary set of `conditions` keyed by any field present in the media data or webhook request object. ```APIDOC ## `findInstances` — Filter Engine Evaluates an ordered list of filters against a webhook payload and its associated TMDB/Overseerr media metadata. Returns the `apply` target (instance name or array of names) for the first matching filter, or `null` if nothing matches. Filters are matched on `media_type`, optional `is_4k`, and an arbitrary set of `conditions` keyed by any field present in the media data or webhook request object. ```typescript import { findInstances } from "./src/services/filter" const webhook = { notification_type: "MEDIA_PENDING", media: { media_type: "tv", tmdbId: "94605", status: "PENDING", status4k: "UNKNOWN" }, request: { request_id: "7", requestedBy_email: "bob@example.com", requestedBy_username: "bob" }, extra: [{ name: "Requested Seasons", value: "1, 2" }], } const mediaData = { originalName: "Arcane", originalLanguage: "en", keywords: [ { id: 161919, name: "adult animation" }, { id: 41645, name: "based on video game" }, ], contentRatings: { results: [ { iso_3166_1: "US", rating: "TV-14" }, { iso_3166_1: "DE", rating: "16" }, ], }, numberOfSeasons: 2, genres: [{ id: 16, name: "Animation" }, { id: 10765, name: "Sci-Fi & Fantasy" }], } const filters = [ // Match animation TV shows with at most 3 seasons, not horror { media_type: "tv", conditions: { keywords: { include: ["animation"], exclude: ["horror"] }, max_seasons: 3, }, apply: "sonarr_anime", }, // Catch-all for English TV { media_type: "tv", conditions: { originalLanguage: "en" }, apply: ["sonarr", "sonarr_4k"], // send to multiple instances }, ] const result = findInstances(webhook as any, mediaData as any, filters as any) // result === "sonarr_anime" (first filter matched) // No-match example: const strictFilters = [ { media_type: "movie", conditions: { originalLanguage: "fr" }, apply: "radarr_fr" }, ] const noMatch = findInstances(webhook as any, mediaData as any, strictFilters as any) // noMatch === null ``` ``` -------------------------------- ### Find Instances with findInstances Source: https://context7.com/varthe/redirecterr/llms.txt Use `findInstances` to evaluate filters against webhook and media data. It returns the `apply` target of the first matching filter or `null` if no filters match. Ensure webhook and media data are correctly structured. ```typescript import { findInstances } from "./src/services/filter" const webhook = { notification_type: "MEDIA_PENDING", media: { media_type: "tv", tmdbId: "94605", status: "PENDING", status4k: "UNKNOWN" }, request: { request_id: "7", requestedBy_email: "bob@example.com", requestedBy_username: "bob" }, extra: [{ name: "Requested Seasons", value: "1, 2" }], } const mediaData = { originalName: "Arcane", originalLanguage: "en", keywords: [ { id: 161919, name: "adult animation" }, { id: 41645, name: "based on video game" }, ], contentRatings: { results: [ { iso_3166_1: "US", rating: "TV-14" }, { iso_3166_1: "DE", rating: "16" }, ], }, numberOfSeasons: 2, genres: [{ id: 16, name: "Animation" }, { id: 10765, name: "Sci-Fi & Fantasy" }], } const filters = [ // Match animation TV shows with at most 3 seasons, not horror { media_type: "tv", conditions: { keywords: { include: ["animation"], exclude: ["horror"] }, max_seasons: 3, }, apply: "sonarr_anime", }, // Catch-all for English TV { media_type: "tv", conditions: { originalLanguage: "en" }, apply: ["sonarr", "sonarr_4k"], // send to multiple instances }, ] const result = findInstances(webhook as any, mediaData as any, filters as any) // result === "sonarr_anime" (first filter matched) // No-match example: const strictFilters = [ { media_type: "movie", conditions: { originalLanguage: "fr" }, apply: "radarr_fr" }, ] const noMatch = findInstances(webhook as any, mediaData as any, strictFilters as any) // noMatch === null ``` -------------------------------- ### `fetchFromOverseerr` / `approveRequest` / `applyConfig` — Overseerr API Client Source: https://context7.com/varthe/redirecterr/llms.txt Three functions wrapping the Overseerr REST API. `fetchFromOverseerr` retrieves full media metadata by TMDB ID. `applyConfig` updates a pending request's instance settings. `approveRequest` approves a request. All use the `X-Api-Key` header from config. ```APIDOC ## `fetchFromOverseerr` / `approveRequest` / `applyConfig` — Overseerr API Client Three functions wrapping the Overseerr REST API. `fetchFromOverseerr` retrieves full media metadata by TMDB ID. `applyConfig` updates a pending request's instance settings. `approveRequest` approves a request. All use the `X-Api-Key` header from config. ```typescript import { fetchFromOverseerr, approveRequest, applyConfig } from "./src/api/overseerr" // Fetch full movie metadata (TMDB ID 558449 = Gladiator II) const movieData = await fetchFromOverseerr("/api/v1/movie/558449") // Returns full TMDB + Overseerr mediaInfo object including keywords, contentRatings, genres, etc. // Fetch TV show metadata (TMDB ID 94605 = Arcane) const showData = await fetchFromOverseerr("/api/v1/tv/94605") // Returns show object with contentRatings.results[], keywords[], numberOfSeasons, etc. // Apply instance config to a pending request await applyConfig("42", { mediaType: "tv", seasons: [1, 2], rootFolder: "/mnt/media/Anime", serverId: 2, profileId: 4, // optional quality profile override }) // PUT http://overseerr:5055/api/v1/request/42 // Approve a request await approveRequest("42") // POST http://overseerr:5055/api/v1/request/42/approve ``` ``` -------------------------------- ### Docker Compose Deployment Configuration Source: https://context7.com/varthe/redirecterr/llms.txt Configuration for deploying Redirecterr using Docker Compose. Includes service definition, ports, volumes for configuration and logs, environment variables, and restart policy. ```yaml # docker-compose.yml services: redirecterr: image: varthe/redirecterr:latest container_name: redirecterr hostname: redirecterr ports: - "8481:8481" volumes: - /path/to/config.yaml:/config/config.yaml - /path/to/logs:/logs environment: - LOG_LEVEL=info # Set to "debug" for verbose filter matching logs restart: unless-stopped # Then in Overseerr: Settings → Notifications → Webhook # Webhook URL: http://redirecterr:8481/webhook # Notification Types: Request Pending Approval # JSON Payload (required format): # { # "notification_type": "{{notification_type}}", # "media": { # "media_type": "{{media_type}}", # "tmdbId": "{{media_tmdbid}}", # "status": "{{media_status}}", # "status4k": "{{media_status4k}}" # }, # "request": { # "request_id": "{{request_id}}", # "requestedBy_email": "{{requestedBy_email}}", # "requestedBy_username": "{{requestedBy_username}}" # }, # "{{extra}}": [] # } ``` -------------------------------- ### matchKeywords Source: https://context7.com/varthe/redirecterr/llms.txt Matches a media item's keyword array against a filter condition using `include` (substring), `require` (exact membership), and `exclude` (substring block) semantics. All specified clauses must pass simultaneously. ```APIDOC ## `matchKeywords` — Keyword Condition Matcher Matches a media item's keyword array against a filter condition using `include` (substring), `require` (exact membership), and `exclude` (substring block) semantics. All specified clauses must pass simultaneously. ```typescript import { matchKeywords } from "./src/services/filter" const keywords = [ { name: "adult animation" }, { name: "based on video game" }, { name: "war" }, ] // include: at least one keyword contains "animation" → true matchKeywords(keywords, { include: "animation" }) // true // require: at least one keyword equals exactly "war" → true matchKeywords(keywords, { require: "war" }) // true // exclude: no keyword contains "horror" → true (no horror keyword present) matchKeywords(keywords, { exclude: "horror" }) // true // exclude: "animation" is present → false matchKeywords(keywords, { exclude: "animation" }) // false // Combined: include "animation", exclude "horror" → true matchKeywords(keywords, { include: "animation", exclude: "horror" }) // true // Combined: require exact "magic" (not present) → false matchKeywords(keywords, { require: "magic", include: "war" }) // false // Simple string shorthand (include semantics) matchKeywords(keywords, "game") // true (substring of "based on video game") ``` ``` -------------------------------- ### Overseerr API Client Functions Source: https://context7.com/varthe/redirecterr/llms.txt Wrappers for the Overseerr REST API to fetch media metadata, apply instance configurations, and approve requests. Uses the `X-Api-Key` header from configuration. ```typescript import { fetchFromOverseerr, approveRequest, applyConfig } from "./src/api/overseerr" // Fetch full movie metadata (TMDB ID 558449 = Gladiator II) const movieData = await fetchFromOverseerr("/api/v1/movie/558449") // Returns full TMDB + Overseerr mediaInfo object including keywords, contentRatings, genres, etc. // Fetch TV show metadata (TMDB ID 94605 = Arcane) const showData = await fetchFromOverseerr("/api/v1/tv/94605") // Returns show object with contentRatings.results[], keywords[], numberOfSeasons, etc. // Apply instance config to a pending request await applyConfig("42", { mediaType: "tv", seasons: [1, 2], rootFolder: "/mnt/media/Anime", serverId: 2, profileId: 4, // optional quality profile override }) // PUT http://overseerr:5055/api/v1/request/42 // Approve a request await approveRequest("42") // POST http://overseerr:5055/api/v1/request/42/approve ``` -------------------------------- ### Instance Dispatcher (`sendToInstances`) Source: https://context7.com/varthe/redirecterr/llms.txt Applies instance-specific configuration and approves Overseerr requests. Handles single or multiple instances, logging individual failures as warnings. Use when `apply` in the matched filter specifies an array. ```typescript import { sendToInstances } from "./src/services/instance" // config.instances must contain entries matching these names // Internally called by handleWebhook after findInstances succeeds // Single instance await sendToInstances("sonarr_anime", "42", { mediaType: "tv", seasons: [1, 2] }) // → PUT /api/v1/request/42 { mediaType: "tv", seasons: [1,2], rootFolder: "/mnt/Anime", serverId: 2 } // → POST /api/v1/request/42/approve // Multiple instances await sendToInstances(["sonarr", "sonarr_4k"], "43", { mediaType: "tv", seasons: [1] }) // → Applies config + approves on "sonarr" // → Applies config + approves on "sonarr_4k" // Instance with approve: false skips the approval step // Instance not found in config.instances → logged as warning, skipped ``` -------------------------------- ### Redirecterr Config: Overseerr Settings Source: https://github.com/varthe/redirecterr/blob/main/README.md Configure the connection details for Overseerr, including its URL and API token. Set `approve_on_no_match` to automatically approve requests if no filters are matched. ```yaml overseerr_url: "" overseerr_api_token: "" approve_on_no_match: true # Auto-approve if no filters match ``` -------------------------------- ### POST /webhook Source: https://context7.com/varthe/redirecterr/llms.txt The sole HTTP entry point for Redirecterr. It accepts Overseerr webhook payloads, validates them, and orchestrates the routing pipeline. ```APIDOC ## POST /webhook ### Description This endpoint accepts Overseerr webhook payloads, validates their structure, and initiates the media routing process based on the `config.yaml` file. ### Method POST ### Endpoint /webhook ### Request Body Accepts a JSON payload from Overseerr containing notification details. ### Request Example ```json { "notification_type": "MEDIA_PENDING", "media": { "media_type": "movie", "tmdbId": "558449", "status": "PENDING", "status4k": "UNKNOWN" }, "request": { "request_id": "42", "requestedBy_email": "alice@example.com", "requestedBy_username": "alice" }, "extra": [] } ``` ### Response #### Success Response - **status** (string) - Indicates the processing status ('success'). - **message** (string) - Describes the outcome, e.g., 'Request processed and sent to instances' or 'Request approved (no matching filter)'. #### Response Example (Routed) ```json { "status": "success", "message": "Request processed and sent to instances" } ``` #### Response Example (No Match, Auto-approve enabled) ```json { "status": "success", "message": "Request approved (no matching filter)" } ``` #### Response Example (Test Notification) ```json { "status": "success", "message": "Test notification received" } ``` ### Notes - Configure Overseerr: Settings → Notifications → Webhook. - Webhook URL: `http://:/webhook` - Notification Types: `Request Pending Approval`. - All other paths or methods return a 400 error. ``` -------------------------------- ### Match Keywords with matchKeywords Source: https://context7.com/varthe/redirecterr/llms.txt Use `matchKeywords` to check if a media item's keywords satisfy filter conditions. Supports `include`, `require`, and `exclude` semantics, and can accept a simple string for basic substring matching. ```typescript import { matchKeywords } from "./src/services/filter" const keywords = [ { name: "adult animation" }, { name: "based on video game" }, { name: "war" }, ] // include: at least one keyword contains "animation" → true matchKeywords(keywords, { include: "animation" }) // true // require: at least one keyword equals exactly "war" → true matchKeywords(keywords, { require: "war" }) // true // exclude: no keyword contains "horror" → true (no horror keyword present) matchKeywords(keywords, { exclude: "horror" }) // true // exclude: "animation" is present → false matchKeywords(keywords, { exclude: "animation" }) // false // Combined: include "animation", exclude "horror" → true matchKeywords(keywords, { include: "animation", exclude: "horror" }) // true // Combined: require exact "magic" (not present) → false matchKeywords(keywords, { require: "magic", include: "war" }) // false // Simple string shorthand (include semantics) matchKeywords(keywords, "game") // true (substring of "based on video game") ``` -------------------------------- ### Match Content Ratings with matchContentRatings Source: https://context7.com/varthe/redirecterr/llms.txt Use `matchContentRatings` to match media content ratings against filter conditions. It supports `include`, `require`, and `exclude` semantics, and can use simple strings for substring matching across all regions. ```typescript import { matchContentRatings } from "./src/services/filter" const contentRatings = { results: [ { iso_3166_1: "US", rating: "TV-14" }, { iso_3166_1: "DE", rating: "16" }, { iso_3166_1: "AU", rating: "MA 15+" }, ], } // Simple string: substring match → "16" is present in DE → true matchContentRatings(contentRatings, "16") // true // include: "14" is a substring of "TV-14" → true matchContentRatings(contentRatings, { include: "14" }) // true // require: exact "TV-14" present → true matchContentRatings(contentRatings, { require: "TV-14" }) // true // exclude: "18" not present in any rating → true matchContentRatings(contentRatings, { exclude: "18" }) // true // exclude: "16" IS present → false (filter blocks this content rating) matchContentRatings(contentRatings, { exclude: "16" }) // false // Combined require + exclude matchContentRatings(contentRatings, { require: "TV-14", exclude: "18" }) // true ``` -------------------------------- ### Webhook Endpoint - POST /webhook Source: https://context7.com/varthe/redirecterr/llms.txt The sole HTTP entry point for Redirecterr. It accepts Overseerr webhook payloads and orchestrates the routing pipeline. Configure Overseerr to send 'Request Pending Approval' notifications to this URL. ```bash # Configure Overseerr: Settings → Notifications → Webhook # Webhook URL: http://redirecterr:8481/webhook # Notification Types: Request Pending Approval curl -X POST http://localhost:8481/webhook \ -H "Content-Type: application/json" \ -d '{ "notification_type": "MEDIA_PENDING", "media": { "media_type": "movie", "tmdbId": "558449", "status": "PENDING", "status4k": "UNKNOWN" }, "request": { "request_id": "42", "requestedBy_email": "alice@example.com", "requestedBy_username": "alice" }, "extra": [] }' # Success response (routed to matched instance): # {"status":"success","message":"Request processed and sent to instances"} # Success response (no filter matched, approve_on_no_match: true): # {"status":"success","message":"Request approved (no matching filter)"} # Test notification acknowledgement: curl -X POST http://localhost:8481/webhook \ -H "Content-Type: application/json" \ -d '{"notification_type":"TEST_NOTIFICATION","media":{},"request":{}}' # {"status":"success","message":"Test notification received"} # Invalid path: curl -X GET http://localhost:8481/health # {"status":"error","message":"Invalid URL. Use the /webhook endpoint"} ``` -------------------------------- ### matchContentRatings Source: https://context7.com/varthe/redirecterr/llms.txt Matches a media item's content ratings array (across all regions) against a filter condition using the same include/exclude/require interface as keyword matching. ```APIDOC ## `matchContentRatings` — Content Rating Condition Matcher Matches a media item's content ratings array (across all regions) against a filter condition using the same include/exclude/require interface as keyword matching. ```typescript import { matchContentRatings } from "./src/services/filter" const contentRatings = { results: [ { iso_3166_1: "US", rating: "TV-14" }, { iso_3166_1: "DE", rating: "16" }, { iso_3166_1: "AU", rating: "MA 15+" }, ], } // Simple string: substring match → "16" is present in DE → true matchContentRatings(contentRatings, "16") // true // include: "14" is a substring of "TV-14" → true matchContentRatings(contentRatings, { include: "14" }) // true // require: exact "TV-14" present → true matchContentRatings(contentRatings, { require: "TV-14" }) // true // exclude: "18" not present in any rating → true matchContentRatings(contentRatings, { exclude: "18" }) // true // exclude: "16" IS present → false (filter blocks this content rating) matchContentRatings(contentRatings, { exclude: "16" }) // false // Combined require + exclude matchContentRatings(contentRatings, { require: "TV-14", exclude: "18" }) // true ``` ``` -------------------------------- ### `matchValue` — Generic Field Value Matcher Source: https://context7.com/varthe/redirecterr/llms.txt A recursive, case-insensitive matcher for arbitrary webhook and media data fields. It traverses nested objects and arrays automatically and is used internally by `findInstances` for non-keyword, non-contentRating condition fields. ```APIDOC ## `matchValue` — Generic Field Value Matcher A recursive, case-insensitive matcher for arbitrary webhook and media data fields. Traverses nested objects and arrays automatically. Used internally by `findInstances` for all non-keyword, non-contentRating condition fields. ```typescript import { matchValue } from "./src/services/filter" // Simple string field — include (substring) semantics (required=false) matchValue("en", "en", false) // true matchValue("action", { name: "Action" }, false) // true (traverses object) // Array field — at least one element matches matchValue("animation", [{ name: "Animation" }, { name: "Drama" }], false) // true matchValue(["action", "drama"], [{ name: "Drama" }], false) // true // required=true: ALL values in filterValue must appear exactly in dataValue matchValue(["Action", "Adventure"], [{ name: "Action" }, { name: "Adventure" }], true) // true matchValue(["Action", "Horror"], [{ name: "Action" }, { name: "Adventure" }], true) // false ("Horror" not found) // Nested object traversal matchValue("paramount", { productionCompanies: [{ name: "Paramount Pictures", originCountry: "US" }] }, false) // true ``` ``` -------------------------------- ### Generic Field Value Matcher (`matchValue`) Source: https://context7.com/varthe/redirecterr/llms.txt Recursively matches values in nested objects and arrays, case-insensitively. Use for non-keyword, non-contentRating conditions. For `required=true`, all filter values must exist in the data value. ```typescript import { matchValue } from "./src/services/filter" // Simple string field — include (substring) semantics (required=false) matchValue("en", "en", false) // true matchValue("action", { name: "Action" }, false) // true (traverses object) // Array field — at least one element matches matchValue("animation", [{ name: "Animation" }, { name: "Drama" }], false) // true matchValue(["action", "drama"], [{ name: "Drama" }], false) // true // required=true: ALL values in filterValue must appear exactly in dataValue matchValue(["Action", "Adventure"], [{ name: "Action" }, { name: "Adventure" }], true) // true matchValue(["Action", "Horror"], [{ name: "Action" }, { name: "Adventure" }], true) // false ("Horror" not found) // Nested object traversal matchValue("paramount", { productionCompanies: [{ name: "Paramount Pictures", originCountry: "US" }] }, false) // true ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.