mirror of
https://github.com/soulis-1256/assemblrr.git
synced 2026-10-19 09:13:33 +00:00
Fix quality profile setup and split Recyclarr into include packs
Always sync HD/UHD (and Sonarr WEB) as include packs, name them with an assemblrr prefix, soften blocking CF scores, zero quality minSize, relax minimumSeeders, and update Seerr on reconfigure. Document TRaSH guide drift and tighten comments and uninstall messaging.
This commit is contained in:
parent
a381de1f8f
commit
bd126b704e
19 changed files with 439 additions and 410 deletions
29
README.md
29
README.md
|
|
@ -95,6 +95,35 @@ Configuration lives in your installation directory (default: `~/assemblrr`).
|
|||
- `compose/custom.yaml`: Optional services (from the example under `compose/examples/`).
|
||||
- `config/`: Persistent service data.
|
||||
|
||||
## Quality Profiles & TRaSH Guides
|
||||
|
||||
assemblrr uses [Recyclarr](https://recyclarr.dev/) to sync [TRaSH Guides](https://trash-guides.info/) quality profiles and custom formats into Radarr and Sonarr.
|
||||
|
||||
**Both resolutions are always installed** as assemblrr-named profiles (movies: **assemblrr HD Bluray + WEB** + **assemblrr UHD Bluray + WEB**; TV: **assemblrr WEB-1080p** + **assemblrr WEB-2160p**). The setup question only picks Seerr’s *default* for movie requests — the other profile stays available in the quality dropdown. Stock Radarr/Sonarr profiles (Any, HD-1080p, …) also appear there; that is normal.
|
||||
|
||||
assemblrr deliberately **does not** apply TRaSH quality min-size limits (they can reject smaller legitimate releases), and softens hard-block custom formats (LQ / x265 / 3D scores set to 0). Tier preferences from the guides still apply when better releases exist.
|
||||
|
||||
**Those guides change over time.** Trash IDs, profile names, and Recyclarr YAML schema can all break without warning. When that happens you may see:
|
||||
|
||||
- Recyclarr sync errors (`Invalid quality profile trash_id`, `YAML error`, etc.)
|
||||
- Seerr defaulting to **Any** instead of your chosen quality
|
||||
- Missing Recyclarr profiles in Radarr/Sonarr (only stock profiles like Any / HD-1080p)
|
||||
|
||||
That is expected community-guide churn — not a VPN or Docker failure.
|
||||
|
||||
### What to do when it breaks
|
||||
|
||||
1. Check Recyclarr: `docker logs recyclarr` and/or `docker exec recyclarr recyclarr sync`
|
||||
2. List current guide IDs from inside the container:
|
||||
```bash
|
||||
docker exec recyclarr recyclarr list quality-profiles radarr
|
||||
docker exec recyclarr recyclarr list quality-profiles sonarr
|
||||
```
|
||||
3. Update the relevant pack under `templates/recyclarr/includes/` (or the live copies in your install’s `config/recyclarr/includes/`) with the new trash IDs. Root config is `templates/recyclarr/recyclarr.yml`.
|
||||
4. Re-run sync, then refresh Seerr: `assemblrr configure`
|
||||
|
||||
We try to keep templates current, but **plan on occasional manual updates** if you rely on TRaSH-backed profiles long-term. Official docs: [Recyclarr](https://recyclarr.dev/) · [TRaSH Guides](https://trash-guides.info/).
|
||||
|
||||
## Development
|
||||
|
||||
### Windows (powershell)
|
||||
|
|
|
|||
|
|
@ -337,7 +337,7 @@ uninstall_app() {
|
|||
log_info "Media directory preserved at $MEDIA_DIRECTORY"
|
||||
fi
|
||||
else
|
||||
log_info "Media directory preserved at $MEDIA_DIRECTORY (pass --media with --force to delete it)"
|
||||
log_info "Media directory preserved at $MEDIA_DIRECTORY"
|
||||
fi
|
||||
|
||||
echo "Removing CLI..."
|
||||
|
|
|
|||
|
|
@ -146,6 +146,16 @@ fi
|
|||
# Configure Recyclarr (must run before Seerr so quality profiles exist in Radarr/Sonarr)
|
||||
configure_recyclarr || true
|
||||
|
||||
# Enforce minSize=0 and record preferred quality profiles after Recyclarr sync.
|
||||
if [ -n "$RADARR_API_KEY" ]; then
|
||||
relax_quality_sizes "Radarr" "7878" "$RADARR_API_KEY" || true
|
||||
set_default_quality_profile "Radarr" "7878" "$RADARR_API_KEY" "lookup_radarr_profile" || true
|
||||
fi
|
||||
if [ -n "$SONARR_API_KEY" ]; then
|
||||
relax_quality_sizes "Sonarr" "8989" "$SONARR_API_KEY" || true
|
||||
set_default_quality_profile "Sonarr" "8989" "$SONARR_API_KEY" "lookup_sonarr_profile" || true
|
||||
fi
|
||||
|
||||
# Configure Seerr (must run after media server is configured AND Recyclarr has synced profiles)
|
||||
configure_seerr || true
|
||||
|
||||
|
|
|
|||
|
|
@ -239,8 +239,13 @@ copy_configuration_files() {
|
|||
["compose/vpn.yaml"]="compose/vpn.yaml"
|
||||
["compose/examples/custom.yaml.example"]="compose/examples/custom.yaml.example"
|
||||
[".env.example"]=".env.example"
|
||||
["templates/recyclarr-ultra_hd.yml"]="templates/recyclarr-ultra_hd.yml"
|
||||
["templates/recyclarr-full_hd.yml"]="templates/recyclarr-full_hd.yml"
|
||||
["templates/recyclarr/recyclarr.yml"]="templates/recyclarr/recyclarr.yml"
|
||||
["templates/recyclarr/includes/radarr-hd.yml"]="templates/recyclarr/includes/radarr-hd.yml"
|
||||
["templates/recyclarr/includes/radarr-uhd.yml"]="templates/recyclarr/includes/radarr-uhd.yml"
|
||||
["templates/recyclarr/includes/radarr-soft-cfs.yml"]="templates/recyclarr/includes/radarr-soft-cfs.yml"
|
||||
["templates/recyclarr/includes/sonarr-web-1080.yml"]="templates/recyclarr/includes/sonarr-web-1080.yml"
|
||||
["templates/recyclarr/includes/sonarr-web-2160.yml"]="templates/recyclarr/includes/sonarr-web-2160.yml"
|
||||
["templates/recyclarr/includes/sonarr-soft-cfs.yml"]="templates/recyclarr/includes/sonarr-soft-cfs.yml"
|
||||
["branding.conf"]="branding.conf"
|
||||
["bin/cli.sh"]="cli.sh"
|
||||
["bin/configure.sh"]="configure.sh"
|
||||
|
|
|
|||
246
lib/arr.sh
246
lib/arr.sh
|
|
@ -48,14 +48,13 @@ set_arr_auth() {
|
|||
|
||||
# --- qBittorrent helpers ---
|
||||
|
||||
# Set qBittorrent credentials and save path using the temp password from container logs
|
||||
# Called once before configuring any *arr service.
|
||||
# On re-runs, tries the final credentials first to avoid triggering brute-force bans.
|
||||
# Set qBittorrent WebUI credentials and default save paths.
|
||||
# Prefer final credentials when already configured (avoids brute-force lockouts).
|
||||
qbit_set_credentials() {
|
||||
local qbit_port=8081
|
||||
local qbit_cookie_jar="/tmp/qb_cookie_jar_init_$$_${qbit_port}"
|
||||
|
||||
# Try logging in with the final credentials first (already set from a previous run)
|
||||
# Idempotent: succeed if final credentials already work
|
||||
if [ -n "$AUTH_USERNAME" ] && [ -n "$AUTH_PASSWORD" ]; then
|
||||
curl -s --connect-timeout 5 -c "$qbit_cookie_jar" \
|
||||
-H "Referer: http://${API_HOST}:${qbit_port}" \
|
||||
|
|
@ -64,7 +63,6 @@ qbit_set_credentials() {
|
|||
local qbit_sid
|
||||
qbit_sid=$(qbit_cookie_sid "$qbit_cookie_jar")
|
||||
if [ -n "$qbit_sid" ]; then
|
||||
# Credentials already set — ensure save path is configured
|
||||
curl -s --connect-timeout 5 \
|
||||
"http://${API_HOST}:${qbit_port}/api/v2/app/setPreferences" \
|
||||
-b "$qbit_cookie_jar" \
|
||||
|
|
@ -77,7 +75,7 @@ qbit_set_credentials() {
|
|||
fi
|
||||
fi
|
||||
|
||||
# Credentials not set yet — use temp password from container logs
|
||||
# First-time setup: temporary password from container logs
|
||||
local wait_time=0
|
||||
local max_wait=60
|
||||
|
||||
|
|
@ -116,7 +114,7 @@ qbit_set_credentials() {
|
|||
return 1
|
||||
}
|
||||
|
||||
# Create a qBittorrent category with a save path
|
||||
# Create or update a qBittorrent category with a save path
|
||||
qbit_create_category() {
|
||||
local service_name="$1"
|
||||
local category="$2"
|
||||
|
|
@ -131,13 +129,20 @@ qbit_create_category() {
|
|||
local qbit_sid
|
||||
qbit_sid=$(qbit_cookie_sid "$qbit_cookie_jar")
|
||||
if [ -n "$qbit_sid" ]; then
|
||||
# createCategory + editCategory so savePath is set whether the category is new or existing
|
||||
curl -s --connect-timeout 10 \
|
||||
"http://${API_HOST}:${qbit_port}/api/v2/torrents/createCategory" \
|
||||
-b "$qbit_cookie_jar" \
|
||||
-H "Referer: http://${API_HOST}:${qbit_port}" \
|
||||
-d "category=${category}&savePath=${save_path}" \
|
||||
2>/dev/null >/dev/null || true
|
||||
log_step "${service_name}: created qBittorrent '${category}' category (${save_path})"
|
||||
curl -s --connect-timeout 10 \
|
||||
"http://${API_HOST}:${qbit_port}/api/v2/torrents/editCategory" \
|
||||
-b "$qbit_cookie_jar" \
|
||||
-H "Referer: http://${API_HOST}:${qbit_port}" \
|
||||
-d "category=${category}&savePath=${save_path}" \
|
||||
2>/dev/null >/dev/null || true
|
||||
log_step "${service_name}: qBittorrent '${category}' category → ${save_path}"
|
||||
else
|
||||
log_step_fail "${service_name}: could not login to qBittorrent to create categories"
|
||||
fi
|
||||
|
|
@ -184,16 +189,16 @@ configure_arr_service() {
|
|||
log_step "${service_name}: root folder ${root_path} already exists"
|
||||
fi
|
||||
|
||||
# 1b. Remove stale auto-detected root folders
|
||||
# Keep only the configured root folder
|
||||
local all_root_folders
|
||||
all_root_folders=$(api_get "$port" "/api/v3/rootfolder" "$apikey")
|
||||
local stale_ids
|
||||
stale_ids=$(echo "$all_root_folders" | jq -r --arg rp "$root_path" '.[] | select(.path != $rp) | .id' 2>/dev/null || echo "")
|
||||
local extra_ids
|
||||
extra_ids=$(echo "$all_root_folders" | jq -r --arg rp "$root_path" '.[] | select(.path != $rp) | .id' 2>/dev/null || echo "")
|
||||
|
||||
for stale_id in $stale_ids; do
|
||||
if [ -n "$stale_id" ]; then
|
||||
api_delete "$port" "/api/v3/rootfolder/${stale_id}" "$apikey" >/dev/null || true
|
||||
log_step "${service_name}: removed stale root folder (id: ${stale_id})"
|
||||
for extra_id in $extra_ids; do
|
||||
if [ -n "$extra_id" ]; then
|
||||
api_delete "$port" "/api/v3/rootfolder/${extra_id}" "$apikey" >/dev/null || true
|
||||
log_step "${service_name}: removed extra root folder (id: ${extra_id})"
|
||||
fi
|
||||
done
|
||||
|
||||
|
|
@ -296,6 +301,81 @@ configure_arr_service() {
|
|||
set_arr_auth "$service_name" "$port" "$apikey"
|
||||
}
|
||||
|
||||
# --- Quality sizes & default profiles ---
|
||||
|
||||
# Set minSize=0 on every quality definition (no minimum file-size filter).
|
||||
# Values live in the *arr DB; they only change when written via this API.
|
||||
relax_quality_sizes() {
|
||||
local service_name="$1"
|
||||
local port="$2"
|
||||
local apikey="$3"
|
||||
|
||||
local defs
|
||||
defs=$(api_get "$port" "/api/v3/qualitydefinition" "$apikey")
|
||||
if [ -z "$defs" ] || [ "$defs" = "[]" ]; then
|
||||
log_step_fail "${service_name}: no quality definitions to update"
|
||||
return 1
|
||||
fi
|
||||
|
||||
# Only minSize is cleared; leave max/preferred alone (bulk update is picky about nulls).
|
||||
local payload
|
||||
payload=$(echo "$defs" | jq '[.[] | .minSize = 0]' 2>/dev/null || echo "")
|
||||
if [ -z "$payload" ]; then
|
||||
log_step_fail "${service_name}: failed to build quality definition payload"
|
||||
return 1
|
||||
fi
|
||||
|
||||
local result
|
||||
result=$(api_put "$port" "/api/v3/qualitydefinition/update" "$apikey" "$payload")
|
||||
if echo "$result" | jq -e 'type == "array"' >/dev/null 2>&1; then
|
||||
log_step "${service_name}: quality minSize set to 0"
|
||||
return 0
|
||||
fi
|
||||
# Fallback: one PUT per definition
|
||||
local ok=0 total=0
|
||||
while IFS= read -r row; do
|
||||
[ -z "$row" ] && continue
|
||||
total=$((total + 1))
|
||||
local id
|
||||
id=$(echo "$row" | jq -r '.id // empty')
|
||||
[ -z "$id" ] && continue
|
||||
if api_put "$port" "/api/v3/qualitydefinition/${id}" "$apikey" "$row" >/dev/null 2>&1; then
|
||||
ok=$((ok + 1))
|
||||
fi
|
||||
done < <(echo "$payload" | jq -c '.[]' 2>/dev/null || true)
|
||||
|
||||
if [ "$ok" -gt 0 ]; then
|
||||
log_step "${service_name}: quality minSize set to 0 (${ok}/${total})"
|
||||
return 0
|
||||
fi
|
||||
log_step_fail "${service_name}: failed to update quality definitions"
|
||||
return 1
|
||||
}
|
||||
|
||||
# Record the preferred quality profile id/name for this install (setup choice).
|
||||
set_default_quality_profile() {
|
||||
local service_name="$1"
|
||||
local port="$2"
|
||||
local apikey="$3"
|
||||
local profile_func="$4"
|
||||
|
||||
local profile profile_id
|
||||
profile=$($profile_func "$apikey")
|
||||
profile_id="${profile%%:*}"
|
||||
local profile_name="${profile##*:}"
|
||||
|
||||
if [ -z "$profile_id" ] || [ "$profile_id" = "1" ] && [ "$profile_name" = "Any" ]; then
|
||||
log_step "${service_name}: preferred quality profile → Any"
|
||||
return 0
|
||||
fi
|
||||
|
||||
if [ -n "${INSTALL_DIR:-}" ]; then
|
||||
mkdir -p "$INSTALL_DIR/config"
|
||||
echo "${profile_id}:${profile_name}" > "$INSTALL_DIR/config/.${service_name,,}-default-quality-profile" 2>/dev/null || true
|
||||
fi
|
||||
log_step "${service_name}: preferred quality profile → ${profile_name} (id ${profile_id})"
|
||||
}
|
||||
|
||||
# --- Quality profile lookup ---
|
||||
|
||||
lookup_radarr_profile() {
|
||||
|
|
@ -308,27 +388,42 @@ lookup_radarr_profile() {
|
|||
return
|
||||
fi
|
||||
|
||||
# Recyclarr creates profiles with names like "Ultra-HD" or "HD Bluray + WEB"
|
||||
# Match by keyword since the exact name depends on TRaSH Guide version
|
||||
# Default Radarr profiles to skip: Any, SD, HD-720p, HD-1080p, HD - 720p/1080p
|
||||
local target_keyword
|
||||
# Prefer assemblrr-named Recyclarr profiles; fall back to stock *arr names.
|
||||
local target_name=""
|
||||
local stock_fallback=""
|
||||
|
||||
if [ "${SEERR_IS_4K:-false}" = "true" ]; then
|
||||
target_keyword="Ultra"
|
||||
target_name="assemblrr UHD Bluray + WEB"
|
||||
stock_fallback="Ultra-HD"
|
||||
elif [ "${SEERR_DEFAULT_PROFILE:-1}" != "1" ]; then
|
||||
target_keyword="Bluray + WEB"
|
||||
target_name="assemblrr HD Bluray + WEB"
|
||||
stock_fallback="HD-1080p"
|
||||
else
|
||||
echo "1:Any"
|
||||
return
|
||||
fi
|
||||
|
||||
local matched
|
||||
matched=$(echo "$profiles_json" | jq -r --arg kw "$target_keyword" '.[] | select(.name | contains($kw)) | select(.name as $n | ["Any","SD","HD-720p","HD-1080p","HD - 720p/1080p"] | index($n) | not) | "\(.id):\(.name)"' 2>/dev/null | head -1 || echo "")
|
||||
matched=$(echo "$profiles_json" | jq -r --arg name "$target_name" '
|
||||
.[] | select(.name == $name) | "\(.id):\(.name)"
|
||||
' 2>/dev/null | head -1 || echo "")
|
||||
|
||||
if [ -n "$matched" ]; then
|
||||
echo "$matched"
|
||||
else
|
||||
echo "1:Any"
|
||||
return
|
||||
fi
|
||||
|
||||
if [ -n "$stock_fallback" ]; then
|
||||
matched=$(echo "$profiles_json" | jq -r --arg name "$stock_fallback" '
|
||||
.[] | select(.name == $name) | "\(.id):\(.name)"
|
||||
' 2>/dev/null | head -1 || echo "")
|
||||
if [ -n "$matched" ]; then
|
||||
echo "$matched"
|
||||
return
|
||||
fi
|
||||
fi
|
||||
|
||||
echo "1:Any"
|
||||
}
|
||||
|
||||
lookup_sonarr_profile() {
|
||||
|
|
@ -337,28 +432,43 @@ lookup_sonarr_profile() {
|
|||
profiles_json=$(api_get "8989" "/api/v3/qualityprofile" "$apikey")
|
||||
|
||||
if [ -z "$profiles_json" ]; then
|
||||
echo "1:Default"
|
||||
echo "1:Any"
|
||||
return
|
||||
fi
|
||||
|
||||
# Recyclarr creates profiles with names like "Ultra-HD" or "WEB-1080p"
|
||||
# Match by keyword since the exact name depends on TRaSH Guide version
|
||||
# Default Sonarr profiles to skip: Any, SD, HD-720p, HD-1080p, HD - 720p/1080p
|
||||
local target_keyword
|
||||
if [ "${SEERR_IS_4K:-false}" = "true" ]; then
|
||||
target_keyword="Ultra"
|
||||
else
|
||||
target_keyword="WEB"
|
||||
fi
|
||||
# Default TV profile is assemblrr WEB-1080p (movies 4K choice does not change this).
|
||||
local target_name="assemblrr WEB-1080p"
|
||||
local stock_fallback="HD-1080p"
|
||||
|
||||
local matched
|
||||
matched=$(echo "$profiles_json" | jq -r --arg kw "$target_keyword" '.[] | select(.name | contains($kw)) | select(.name as $n | ["Any","SD","HD-720p","HD-1080p","HD - 720p/1080p"] | index($n) | not) | "\(.id):\(.name)"' 2>/dev/null | head -1 || echo "")
|
||||
matched=$(echo "$profiles_json" | jq -r --arg name "$target_name" '
|
||||
.[] | select(.name == $name) | "\(.id):\(.name)"
|
||||
' 2>/dev/null | head -1 || echo "")
|
||||
|
||||
if [ -n "$matched" ]; then
|
||||
echo "$matched"
|
||||
else
|
||||
echo "1:Default"
|
||||
return
|
||||
fi
|
||||
|
||||
matched=$(echo "$profiles_json" | jq -r '
|
||||
.[] | select(.name | test("^assemblrr.*WEB.*1080"; "i")) | "\(.id):\(.name)"
|
||||
' 2>/dev/null | head -1 || echo "")
|
||||
if [ -n "$matched" ]; then
|
||||
echo "$matched"
|
||||
return
|
||||
fi
|
||||
|
||||
if [ -n "$stock_fallback" ]; then
|
||||
matched=$(echo "$profiles_json" | jq -r --arg name "$stock_fallback" '
|
||||
.[] | select(.name == $name) | "\(.id):\(.name)"
|
||||
' 2>/dev/null | head -1 || echo "")
|
||||
if [ -n "$matched" ]; then
|
||||
echo "$matched"
|
||||
return
|
||||
fi
|
||||
fi
|
||||
|
||||
echo "1:Any"
|
||||
}
|
||||
|
||||
# --- Radarr configuration ---
|
||||
|
|
@ -374,6 +484,58 @@ configure_radarr() {
|
|||
|
||||
# --- Prowlarr configuration ---
|
||||
|
||||
# Set minimumSeeders=0 on Prowlarr app profiles and *arr indexers.
|
||||
# Peer counts from indexers are often incomplete; requiring seeders>=1 blocks valid grabs.
|
||||
relax_minimum_seeders() {
|
||||
local prowlarr_key="$1"
|
||||
local radarr_key="${2:-}"
|
||||
local sonarr_key="${3:-}"
|
||||
|
||||
local profiles
|
||||
profiles=$(api_get "9696" "/api/v1/appprofile" "$prowlarr_key")
|
||||
if [ -n "$profiles" ] && [ "$profiles" != "[]" ]; then
|
||||
local profile_id profile_payload
|
||||
while IFS= read -r row; do
|
||||
[ -z "$row" ] && continue
|
||||
profile_id=$(echo "$row" | jq -r '.id // empty')
|
||||
[ -z "$profile_id" ] && continue
|
||||
profile_payload=$(echo "$row" | jq '.minimumSeeders = 0' 2>/dev/null || echo "")
|
||||
[ -z "$profile_payload" ] && continue
|
||||
if api_put "9696" "/api/v1/appprofile/${profile_id}" "$prowlarr_key" "$profile_payload" >/dev/null 2>&1; then
|
||||
log_step "Prowlarr: app profile '${profile_id}' minimumSeeders → 0"
|
||||
fi
|
||||
done < <(echo "$profiles" | jq -c '.[]' 2>/dev/null || true)
|
||||
fi
|
||||
|
||||
local port key name
|
||||
for port_key_name in "7878:${radarr_key}:Radarr" "8989:${sonarr_key}:Sonarr"; do
|
||||
port="${port_key_name%%:*}"
|
||||
rest="${port_key_name#*:}"
|
||||
key="${rest%%:*}"
|
||||
name="${rest#*:}"
|
||||
[ -z "$key" ] && continue
|
||||
|
||||
local indexers
|
||||
indexers=$(api_get "$port" "/api/v3/indexer" "$key")
|
||||
[ -z "$indexers" ] || [ "$indexers" = "[]" ] && continue
|
||||
|
||||
while IFS= read -r idx; do
|
||||
[ -z "$idx" ] && continue
|
||||
local idx_id idx_payload
|
||||
idx_id=$(echo "$idx" | jq -r '.id // empty')
|
||||
[ -z "$idx_id" ] && continue
|
||||
idx_payload=$(echo "$idx" | jq '
|
||||
.fields = [.fields[] |
|
||||
if .name == "minimumSeeders" then .value = 0 else . end
|
||||
]
|
||||
' 2>/dev/null || echo "")
|
||||
[ -z "$idx_payload" ] && continue
|
||||
api_put "$port" "/api/v3/indexer/${idx_id}" "$key" "$idx_payload" >/dev/null 2>&1 || true
|
||||
done < <(echo "$indexers" | jq -c '.[]' 2>/dev/null || true)
|
||||
log_step "${name}: indexer minimumSeeders → 0"
|
||||
done
|
||||
}
|
||||
|
||||
configure_prowlarr() {
|
||||
local apikey="$1"
|
||||
local radarr_apikey="$2"
|
||||
|
|
@ -436,8 +598,8 @@ configure_prowlarr() {
|
|||
fi
|
||||
fi
|
||||
|
||||
# 2. Add public indexers
|
||||
echo "Adding ${#PUBLIC_INDEXERS[@]} indexer(s) to Prowlarr" >&2
|
||||
# 2. Add selected indexers
|
||||
echo "Adding ${#SELECTED_INDEXERS[@]} indexer(s) to Prowlarr" >&2
|
||||
local indexer_schemas
|
||||
indexer_schemas=$(api_get "9696" "/api/v1/indexer/schema" "$apikey")
|
||||
|
||||
|
|
@ -452,7 +614,7 @@ configure_prowlarr() {
|
|||
local existing_names
|
||||
existing_names=$(jq_json_list_values "$existing_indexers" "name")
|
||||
|
||||
for indexer_name in ${PUBLIC_INDEXERS[@]+"${PUBLIC_INDEXERS[@]}"}; do
|
||||
for indexer_name in ${SELECTED_INDEXERS[@]+"${SELECTED_INDEXERS[@]}"}; do
|
||||
# Skip if already added
|
||||
if echo "$existing_names" | grep -q -F -x "$indexer_name"; then
|
||||
log_step "Prowlarr: ${indexer_name} indexer already exists"
|
||||
|
|
@ -502,7 +664,9 @@ configure_prowlarr() {
|
|||
echo >&2
|
||||
log_success "Indexers added to Prowlarr!" >&2
|
||||
|
||||
# 3. Set authentication
|
||||
relax_minimum_seeders "$apikey" "$radarr_apikey" "${sonarr_apikey:-}"
|
||||
|
||||
# 4. Set authentication
|
||||
set_arr_auth "Prowlarr" "9696" "$apikey" "v1"
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -245,7 +245,7 @@ prepare_install_dirs() {
|
|||
"scripts"
|
||||
)
|
||||
|
||||
# Reclaim install root if a previous run left it root-owned
|
||||
# Ensure install root is owned by the target user
|
||||
if [ -d "$install_dir" ] && [ ! -w "$install_dir" ]; then
|
||||
ensure_owned "$install_dir" "$(id -u)" "$(id -g)"
|
||||
fi
|
||||
|
|
|
|||
|
|
@ -1,12 +1,12 @@
|
|||
#!/bin/bash
|
||||
# fzf-based TUI for selections (Prowlarr indexers, Jellyfin languages)
|
||||
# Provides reusable fzf selection patterns for assemblrr.
|
||||
# Sets PUBLIC_INDEXERS array for indexers.
|
||||
# Sets SELECTED_INDEXERS array for Prowlarr.
|
||||
# Usage: source lib/fzf-tui.sh; configure_indexers "$api_key"
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
PUBLIC_INDEXERS=()
|
||||
SELECTED_INDEXERS=()
|
||||
|
||||
# --- TTY detection (reused across functions) ---
|
||||
_fzf_has_tty() {
|
||||
|
|
@ -73,8 +73,8 @@ fzf_single_select() {
|
|||
}
|
||||
|
||||
# --- Generic multi-select fzf (for indexers) ---
|
||||
# Args: $1 = data_source (jq expression or curl), $2 = awk filter
|
||||
# Sets PUBLIC_INDEXERS array
|
||||
# Args: $1 = tab-separated list lines
|
||||
# Sets SELECTED_INDEXERS array
|
||||
fzf_multi_select() {
|
||||
local data="$1"
|
||||
local has_tty=false
|
||||
|
|
@ -104,20 +104,20 @@ fzf_multi_select() {
|
|||
|
||||
if [ -n "$selected" ]; then
|
||||
while IFS= read -r idx; do
|
||||
[ -n "$idx" ] && PUBLIC_INDEXERS+=("$idx")
|
||||
[ -n "$idx" ] && SELECTED_INDEXERS+=("$idx")
|
||||
done <<< "$selected"
|
||||
echo "Selected ${#PUBLIC_INDEXERS[@]} indexer(s): $(IFS=,; echo "${PUBLIC_INDEXERS[*]}")" >&2
|
||||
echo "Selected ${#SELECTED_INDEXERS[@]} indexer(s): $(IFS=,; echo "${SELECTED_INDEXERS[*]}")" >&2
|
||||
else
|
||||
echo "No indexers selected." >&2
|
||||
fi
|
||||
else
|
||||
# No TTY or no fzf — show top public indexers and prompt
|
||||
echo "No interactive terminal available — listing popular public indexers." >&2
|
||||
echo "$data" | jq -r 'sort_by(.name | ascii_downcase) | .[0:20][] | " \(.name)"' 2>/dev/null >&2
|
||||
# No TTY or no fzf — list options and prompt
|
||||
echo "No interactive terminal available — listing available indexers." >&2
|
||||
echo "$data" | cut -f1 | head -20 | sed 's/^/ /' >&2
|
||||
echo "Enter indexer names separated by spaces (or blank to skip):" >&2
|
||||
read -r input_line || true
|
||||
for idx in $input_line; do
|
||||
PUBLIC_INDEXERS+=("$idx")
|
||||
SELECTED_INDEXERS+=("$idx")
|
||||
done
|
||||
fi
|
||||
}
|
||||
|
|
|
|||
134
lib/seerr.sh
134
lib/seerr.sh
|
|
@ -7,8 +7,9 @@
|
|||
|
||||
set -euo pipefail
|
||||
|
||||
# --- Shared helper: connect a service (Radarr/Sonarr) to Seerr ---
|
||||
# Usage: seerr_connect_service <service_type> <port> <api_key> <profile_func> <active_dir> <is_4k> <cookie_jar>
|
||||
# --- Shared helper: connect or update a service (Radarr/Sonarr) in Seerr ---
|
||||
# Usage: seerr_connect_service <service_type> <port> <api_key> <profile_func> <active_dir> <is_4k> <cookie_jar> [existing_id]
|
||||
# With existing_id: PUT update; without: POST create.
|
||||
# Example: seerr_connect_service "radarr" 7878 "$RADARR_API_KEY" "lookup_radarr_profile" "/data/media/movies" "true" "$cookie_jar"
|
||||
seerr_connect_service() {
|
||||
local service_type="$1"
|
||||
|
|
@ -18,6 +19,7 @@ seerr_connect_service() {
|
|||
local active_dir="$5"
|
||||
local is_4k="$6"
|
||||
local cookie_jar="$7"
|
||||
local existing_id="${8:-}"
|
||||
|
||||
if [ -z "$api_key" ]; then
|
||||
log_step_fail "Seerr: ${service_type} API key not provided"
|
||||
|
|
@ -29,13 +31,12 @@ seerr_connect_service() {
|
|||
return 1
|
||||
fi
|
||||
|
||||
# Look up quality profile from the service (created by Recyclarr)
|
||||
local profile
|
||||
profile=$($profile_func "$api_key")
|
||||
local profile_id="${profile%%:*}"
|
||||
local profile_name="${profile##*:}"
|
||||
|
||||
# Build the service payload
|
||||
# id is read-only on PUT — omit it from the body
|
||||
local payload
|
||||
payload=$(cat <<EOF
|
||||
{
|
||||
|
|
@ -62,15 +63,29 @@ EOF
|
|||
payload=$(echo "$payload" | jq '.enableSeasonFolders = true' 2>/dev/null || echo "$payload")
|
||||
fi
|
||||
|
||||
# POST to Seerr
|
||||
local http_code
|
||||
if [ -n "$existing_id" ]; then
|
||||
http_code=$(curl -s -o /dev/null -w "%{http_code}" --connect-timeout 5 -X PUT -b "$cookie_jar" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d "$payload" \
|
||||
"http://${API_HOST}:5055/api/v1/settings/${service_type}/${existing_id}" 2>/dev/null || echo "000")
|
||||
if [ "$http_code" -ge 200 ] && [ "$http_code" -lt 300 ]; then
|
||||
log_step "Seerr: updated ${service_type^} profile → ${profile_name}"
|
||||
return 0
|
||||
else
|
||||
log_step_fail "Seerr: failed to update ${service_type} (HTTP $http_code)"
|
||||
return 1
|
||||
fi
|
||||
fi
|
||||
|
||||
# POST new connection
|
||||
http_code=$(curl -s -o /dev/null -w "%{http_code}" --connect-timeout 5 -X POST -b "$cookie_jar" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d "$payload" \
|
||||
"http://${API_HOST}:5055/api/v1/settings/${service_type}" 2>/dev/null || echo "000")
|
||||
|
||||
if [ "$http_code" -ge 200 ] && [ "$http_code" -lt 300 ]; then
|
||||
log_step "Seerr: connected ${service_type^}"
|
||||
log_step "Seerr: connected ${service_type^} (profile: ${profile_name})"
|
||||
return 0
|
||||
else
|
||||
log_step_fail "Seerr: failed to connect ${service_type} (HTTP $http_code)"
|
||||
|
|
@ -99,6 +114,24 @@ seerr_service_connected() {
|
|||
return 0
|
||||
}
|
||||
|
||||
# --- Shared helper: first existing Seerr server id for a service (or empty) ---
|
||||
# Usage: seerr_service_id <service_type> <cookie_jar>
|
||||
seerr_service_id() {
|
||||
local service_type="$1"
|
||||
local cookie_jar="$2"
|
||||
|
||||
local settings
|
||||
settings=$(curl -sf --connect-timeout 5 -b "$cookie_jar" \
|
||||
"http://${API_HOST}:5055/api/v1/settings/${service_type}" 2>/dev/null || echo "")
|
||||
|
||||
if [ -z "$settings" ] || [ "$settings" = "[]" ]; then
|
||||
echo ""
|
||||
return 1
|
||||
fi
|
||||
|
||||
echo "$settings" | jq -r '.[0].id // empty' 2>/dev/null || echo ""
|
||||
}
|
||||
|
||||
# --- Shared helper: get Seerr session cookie ---
|
||||
# Usage: seerr_get_cookie <cookie_jar> <include_hostname>
|
||||
# Returns 0 on success, cookie file will be populated
|
||||
|
|
@ -158,42 +191,60 @@ EOF
|
|||
|
||||
configure_recyclarr() {
|
||||
local recyclarr_config_dir="$INSTALL_DIR/config/recyclarr"
|
||||
mkdir -p "$recyclarr_config_dir"
|
||||
local template_root="$INSTALL_DIR/templates/recyclarr"
|
||||
mkdir -p "$recyclarr_config_dir/includes"
|
||||
|
||||
if [ ! -w "$recyclarr_config_dir" ]; then
|
||||
log_step_fail "Recyclarr: config directory not writable (${recyclarr_config_dir})"
|
||||
return 1
|
||||
fi
|
||||
|
||||
# Export variables for envsubst
|
||||
# Only substitute known vars so $schema in YAML comments is left alone
|
||||
export RADARR_API_KEY SONARR_API_KEY
|
||||
|
||||
# Pick the right template based on user's 4K choice
|
||||
local template_file="recyclarr-full_hd.yml" # default: 1080p
|
||||
local profile_label="HD Bluray + WEB"
|
||||
local default_label="assemblrr HD Bluray + WEB"
|
||||
if [ "${SEERR_IS_4K}" = "true" ]; then
|
||||
template_file="recyclarr-ultra_hd.yml" # 4K
|
||||
profile_label="UHD Bluray + WEB"
|
||||
default_label="assemblrr UHD Bluray + WEB"
|
||||
fi
|
||||
|
||||
if [ -f "$INSTALL_DIR/templates/${template_file}" ]; then
|
||||
if envsubst < "$INSTALL_DIR/templates/${template_file}" > "$recyclarr_config_dir/recyclarr.yml"; then
|
||||
log_step "Recyclarr: generated config (${profile_label} profile)"
|
||||
else
|
||||
if [ ! -f "$template_root/recyclarr.yml" ]; then
|
||||
log_step_fail "Recyclarr: template root not found (${template_root}/recyclarr.yml)"
|
||||
return 1
|
||||
fi
|
||||
|
||||
if ! envsubst '${RADARR_API_KEY} ${SONARR_API_KEY}' \
|
||||
< "$template_root/recyclarr.yml" \
|
||||
> "$recyclarr_config_dir/recyclarr.yml"; then
|
||||
log_step_fail "Recyclarr: failed to write config (${recyclarr_config_dir}/recyclarr.yml)"
|
||||
return 1
|
||||
fi
|
||||
else
|
||||
log_step_fail "Recyclarr: template ${template_file} not found"
|
||||
|
||||
# Include packs (no secrets). Replace the directory contents with the template set.
|
||||
local include_src="$template_root/includes"
|
||||
if [ ! -d "$include_src" ]; then
|
||||
log_step_fail "Recyclarr: includes directory not found (${include_src})"
|
||||
return 1
|
||||
fi
|
||||
rm -f "$recyclarr_config_dir/includes"/*.yml 2>/dev/null || true
|
||||
if ! cp "$include_src"/*.yml "$recyclarr_config_dir/includes/"; then
|
||||
log_step_fail "Recyclarr: failed to copy include packs"
|
||||
return 1
|
||||
fi
|
||||
|
||||
# Trigger a sync
|
||||
local pack_count
|
||||
pack_count=$(find "$recyclarr_config_dir/includes" -maxdepth 1 -name '*.yml' | wc -l | tr -d ' ')
|
||||
log_step "Recyclarr: generated config (${pack_count} include packs; Seerr default: ${default_label})"
|
||||
|
||||
_cfg_log_info "Recyclarr: syncing TRaSH Guides to Radarr and Sonarr... this might take a moment"
|
||||
if docker exec recyclarr recyclarr sync > /dev/null 2>&1; then
|
||||
local sync_out
|
||||
if sync_out=$(docker exec recyclarr recyclarr sync 2>&1); then
|
||||
log_step "Recyclarr: synced Custom Formats and Quality Profiles successfully"
|
||||
else
|
||||
log_step_fail "Recyclarr: failed to sync to Radarr/Sonarr (check docker logs recyclarr)"
|
||||
log_step_fail "Recyclarr: failed to sync to Radarr/Sonarr"
|
||||
echo "$sync_out" | grep -E '•|Error|error|Invalid|YAML' | head -5 | while IFS= read -r line; do
|
||||
_cfg_log_info " $line"
|
||||
done
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
|
|
@ -245,31 +296,21 @@ configure_seerr() {
|
|||
|
||||
echo "Connecting Seerr services" >&2
|
||||
|
||||
# Connect Radarr if not already connected
|
||||
if [ -n "$RADARR_API_KEY" ]; then
|
||||
local radarr_count
|
||||
radarr_count=$(seerr_service_connected "radarr" "$seerr_cookie_jar") || radarr_count=0
|
||||
if [ "$radarr_count" -eq 0 ]; then
|
||||
local radarr_id
|
||||
radarr_id=$(seerr_service_id "radarr" "$seerr_cookie_jar" || true)
|
||||
if ! seerr_connect_service "radarr" 7878 "$RADARR_API_KEY" "lookup_radarr_profile" \
|
||||
"/data/media/movies" "${SEERR_IS_4K:-false}" "$seerr_cookie_jar"; then
|
||||
log_step_fail "Seerr: failed to connect Radarr (re-run to retry)"
|
||||
fi
|
||||
else
|
||||
log_step "Seerr: Radarr already connected"
|
||||
"/data/media/movies" "${SEERR_IS_4K:-false}" "$seerr_cookie_jar" "$radarr_id"; then
|
||||
log_step_fail "Seerr: failed to configure Radarr (re-run to retry)"
|
||||
fi
|
||||
fi
|
||||
|
||||
# Connect Sonarr if not already connected
|
||||
if [ -n "$SONARR_API_KEY" ]; then
|
||||
local sonarr_count
|
||||
sonarr_count=$(seerr_service_connected "sonarr" "$seerr_cookie_jar") || sonarr_count=0
|
||||
if [ "$sonarr_count" -eq 0 ]; then
|
||||
local sonarr_id
|
||||
sonarr_id=$(seerr_service_id "sonarr" "$seerr_cookie_jar" || true)
|
||||
if ! seerr_connect_service "sonarr" 8989 "$SONARR_API_KEY" "lookup_sonarr_profile" \
|
||||
"/data/media/tv" "false" "$seerr_cookie_jar"; then
|
||||
log_step_fail "Seerr: failed to connect Sonarr (re-run to retry)"
|
||||
fi
|
||||
else
|
||||
log_step "Seerr: Sonarr already connected"
|
||||
"/data/media/tv" "false" "$seerr_cookie_jar" "$sonarr_id"; then
|
||||
log_step_fail "Seerr: failed to configure Sonarr (re-run to retry)"
|
||||
fi
|
||||
fi
|
||||
|
||||
|
|
@ -350,8 +391,7 @@ EOF
|
|||
return 1
|
||||
fi
|
||||
|
||||
# Check for error in response — "hostname already configured" means media server
|
||||
# was connected by a previous run, which is fine (admin user already exists)
|
||||
# "already configured" is success when re-running against an initialized Seerr
|
||||
local auth_error
|
||||
auth_error=$(echo "$auth_response" | jq -r '.error // ""' 2>/dev/null || echo "")
|
||||
if [ -n "$auth_error" ]; then
|
||||
|
|
@ -365,7 +405,6 @@ EOF
|
|||
return 1
|
||||
fi
|
||||
else
|
||||
# Successful auth — verify admin user was created
|
||||
local auth_id
|
||||
auth_id=$(echo "$auth_response" | jq -r '.id // ""' 2>/dev/null || echo "")
|
||||
if [ -n "$auth_id" ]; then
|
||||
|
|
@ -377,12 +416,10 @@ EOF
|
|||
fi
|
||||
fi
|
||||
|
||||
# Step 5: Get a session cookie for subsequent API calls
|
||||
# Step 5: session cookie for subsequent API calls
|
||||
local seerr_cookie_jar="/tmp/seerr_cookie_jar_$$_${seerr_port}"
|
||||
|
||||
# Get session cookie (with hostname for initial setup)
|
||||
if ! seerr_get_cookie "$seerr_cookie_jar" "true"; then
|
||||
# Retry with login-only if first attempt fails (hostname already configured)
|
||||
if ! seerr_get_cookie "$seerr_cookie_jar" "false"; then
|
||||
log_step_fail "Seerr: failed to get session cookie"
|
||||
rm -f "$seerr_cookie_jar"
|
||||
|
|
@ -390,10 +427,7 @@ EOF
|
|||
fi
|
||||
fi
|
||||
|
||||
# Note: Library sync is skipped here — Jellyfin hasn't indexed anything yet on first setup.
|
||||
# Seerr will auto-sync libraries periodically (every 24h) once content exists.
|
||||
|
||||
# Step 6: Initialize Seerr (mark setup as complete)
|
||||
# Step 6: mark setup complete
|
||||
local init_code
|
||||
init_code=$(curl -s -o /dev/null -w "%{http_code}" --connect-timeout 5 -X POST -b "$seerr_cookie_jar" \
|
||||
-H "Content-Type: application/json" \
|
||||
|
|
|
|||
|
|
@ -250,7 +250,9 @@ cp /tmp/$AppName/compose/base.yaml /tmp/$AppName/compose/vpn.yaml /tmp/$AppName/
|
|||
mkdir -p "`$INSTALL_DIR/compose/examples"
|
||||
cp /tmp/$AppName/compose/examples/custom.yaml.example "`$INSTALL_DIR/compose/examples/" 2>/dev/null || true
|
||||
cp /tmp/$AppName/.env.example "`$INSTALL_DIR/" 2>/dev/null || true
|
||||
cp /tmp/$AppName/templates/recyclarr-full_hd.yml /tmp/$AppName/templates/recyclarr-ultra_hd.yml "`$INSTALL_DIR/templates/"
|
||||
mkdir -p "`$INSTALL_DIR/templates/recyclarr/includes"
|
||||
cp /tmp/$AppName/templates/recyclarr/recyclarr.yml "`$INSTALL_DIR/templates/recyclarr/"
|
||||
cp /tmp/$AppName/templates/recyclarr/includes/*.yml "`$INSTALL_DIR/templates/recyclarr/includes/"
|
||||
mkdir -p "`$INSTALL_DIR/scripts"
|
||||
cp /tmp/$AppName/scripts/* "`$INSTALL_DIR/scripts/"
|
||||
echo "Files synced to install directory"
|
||||
|
|
|
|||
|
|
@ -1,146 +0,0 @@
|
|||
# yaml-language-server: $schema=https://schemas.recyclarr.dev/v8/config-schema.json
|
||||
# HD Bluray + WEB profile (1080p) — used when user chooses non-4K
|
||||
# Template: recyclarr-full_hd.yml
|
||||
|
||||
radarr:
|
||||
radarr-instance:
|
||||
base_url: http://radarr:7878
|
||||
api_key: ${RADARR_API_KEY}
|
||||
|
||||
quality_definition:
|
||||
type: movie
|
||||
|
||||
quality_profiles:
|
||||
- name: HD Bluray + WEB
|
||||
reset_unmatched_scores:
|
||||
enabled: true
|
||||
upgrade:
|
||||
allowed: true
|
||||
until_quality: Bluray-1080p
|
||||
until_score: 10000
|
||||
min_format_score: 0
|
||||
quality_sort: top
|
||||
qualities:
|
||||
- name: Bluray-1080p
|
||||
- name: WEB 1080p
|
||||
qualities:
|
||||
- WEBDL-1080p
|
||||
- WEBRip-1080p
|
||||
- name: Bluray-720p
|
||||
|
||||
custom_formats:
|
||||
# HQ Release Groups + Misc + Unwanted
|
||||
- trash_ids:
|
||||
- ed27ebfef2f323e964fb1f61391bcb35 # HD Bluray Tier 01
|
||||
- c20c8647f2746a1f4c4262b0fbbeeeae # HD Bluray Tier 02
|
||||
- 5608c71bcebba0a5e666223bae8c9227 # HD Bluray Tier 03
|
||||
- c20f169ef63c5f40c2def54abaf4438e # WEB Tier 01
|
||||
- 403816d65392c79236dcb6dd591aeda4 # WEB Tier 02
|
||||
- af94e0fe497124d1f9ce732069ec8c3b # WEB Tier 03
|
||||
- e7718d7a3ce595f289bfee26adc178f5 # Repack/Proper
|
||||
- ae43b294509409a6a13919dedd4764c4 # Repack2
|
||||
- 5caaaa1c08c1742aa4342d8c4cc463f2 # Repack3
|
||||
- ed38b889b31be83fda192888e2286d83 # BR-DISK
|
||||
- e6886871085226c3da1830830146846c # Generated Dynamic HDR
|
||||
- 90a6f9a284dff5103f6346090e6280c8 # LQ
|
||||
- e204b80c87be9497a8a6eaff48f72905 # LQ (Release Title)
|
||||
- dc98083864ea246d05a42df0d05f81cc # x265 (HD)
|
||||
- b8cd450cbfa689c0259a01d9e29ba3d6 # 3D
|
||||
- bfd8eb01832d646a0a89c4deb46f8564 # Upscaled
|
||||
- 0a3f082873eb454bde444150b70253cc # Extras
|
||||
- 712d74cd88bceb883ee32f773656b1f5 # Sing-Along Versions
|
||||
- cae4ca30163749b891686f95532519bd # AV1
|
||||
- cc5e51a9e85a6296ceefe097a77f12f4 # BCORE
|
||||
- 16622a6911d1ab5d5b8b713d5b0036d4 # CRiT
|
||||
- 2a6039655313bf5dab1e43523b62c374 # MA
|
||||
assign_scores_to:
|
||||
- name: HD Bluray + WEB
|
||||
|
||||
# Streaming Services
|
||||
- trash_ids:
|
||||
- b3b3a6ac74ecbd56bcdbefa4799fb9df # AMZN
|
||||
- 40e9380490e748672c2522eaaeb692f7 # ATVP
|
||||
- 84272245b2988854bfb76a16e60baea5 # DSNP
|
||||
- 509e5f41146e278f9eab1ddaceb34515 # HBO
|
||||
- 5763d1b0ce84aff3b21038eea8e9b8ad # HMAX
|
||||
- 526d445d4c16214309f0fd2b3be18a89 # Hulu
|
||||
- e0ec9672be6cac914ffad34a6b077209 # iT
|
||||
- 6a061313d22e51e0f25b7cd4dc065233 # MAX
|
||||
- 170b1d363bd8516fbf3a3eb05d4faff6 # NF
|
||||
- c9fd353f8f5f1baf56dc601c4cb29920 # PCOK
|
||||
- e36a0ba1bc902b26ee40818a1d59b8bd # PMTP
|
||||
- c2863d2a50c9acad1fb50e53ece60817 # STAN
|
||||
assign_scores_to:
|
||||
- name: HD Bluray + WEB
|
||||
|
||||
# Audio - Uncomment to enable Advanced Audio Formats
|
||||
- trash_ids:
|
||||
# - 496f355514737f7d83bf7aa4d24f8169 # TrueHD Atmos
|
||||
# - 2f22d89048b01681dde8afe203bf2e95 # DTS X
|
||||
# - 417804f7f2c4308c1f4c5d380d4c4475 # ATMOS (undefined)
|
||||
# - 1af239278386be2919e1bcee0bde047e # DD+ ATMOS
|
||||
# - 3cafb66171b47f226146a0770576870f # TrueHD
|
||||
# - dcf3ec6938fa32445f590a4da84256cd # DTS-HD MA
|
||||
# - a570d4a0e56a2874b64e5bfa55202a1b # FLAC
|
||||
# - e7c2fcae07cbada050a0af3357491d7b # PCM
|
||||
# - 8e109e50e0a0b83a5098b056e13bf6db # DTS-HD HRA
|
||||
# - 185f1dd7264c4562b9022d963ac37424 # DD+
|
||||
# - f9f847ac70a0af62ea4a08280b859636 # DTS-ES
|
||||
# - 1c1a4c5e823891c75bc50380a6866f73 # DTS
|
||||
# - 240770601cc226190c367ef59aba7463 # AAC
|
||||
# - c2998bd0d90ed5621d8df281e839436e # DD
|
||||
assign_scores_to:
|
||||
- name: HD Bluray + WEB
|
||||
|
||||
# Movie Versions - Uncomment to prefer specific versions
|
||||
- trash_ids:
|
||||
# - 570bc9ebecd92723d2d21500f4be314c # Remaster
|
||||
# - eca37840c13c6ef2dd0262b141a5482f # 4K Remaster
|
||||
# - e0c07d59beb37348e975a930d5e50319 # Criterion Collection
|
||||
# - 9d27d9d2181838f76dee150882bdc58c # Masters of Cinema
|
||||
# - db9b4c4b53d312a3ca5f1378f6440fc9 # Vinegar Syndrome
|
||||
# - 957d0f44b592285f26449575e8b1167e # Special Edition
|
||||
# - eecf3a857724171f968a66cb5719e152 # IMAX
|
||||
# - 9f6cbff8cfe4ebbc1bde14c7b7bec0de # IMAX Enhanced
|
||||
assign_scores_to:
|
||||
- name: HD Bluray + WEB
|
||||
|
||||
# Optional Unwanted
|
||||
- trash_ids:
|
||||
# - b6832f586342ef70d9c128d40c07b872 # Bad Dual Groups
|
||||
# - cc444569854e9de0b084ab2b8b1532b2 # Black and White Editions
|
||||
# - ae9b7c9ebde1f3bd336a8cbd1ec4c5e5 # No-RlsGroup
|
||||
# - 7357cf5161efbf8c4d5d0c30b4815ee2 # Obfuscated
|
||||
# - 5c44f52a8714fdd79bb4d98e2673be1f # Retags
|
||||
# - f537cf427b64c38c8e36298f657e4828 # Scene
|
||||
assign_scores_to:
|
||||
- name: HD Bluray + WEB
|
||||
|
||||
sonarr:
|
||||
sonarr-instance:
|
||||
base_url: http://sonarr:8989
|
||||
api_key: ${SONARR_API_KEY}
|
||||
|
||||
quality_definition:
|
||||
type: series
|
||||
|
||||
quality_profiles:
|
||||
- trash_id: a5ffae4bbda71217e132ce4ed37367c0 # WEB-1080p
|
||||
reset_unmatched_scores:
|
||||
enabled: true
|
||||
|
||||
custom_format_groups:
|
||||
add:
|
||||
- trash_id: 7a2ba4144a594826d4ac03515b371937 # [Optional] Streaming Services
|
||||
select_all: true
|
||||
|
||||
custom_formats:
|
||||
# Optional
|
||||
- trash_ids:
|
||||
# - 32b367365729d530ca1c124a0b180c64 # Bad Dual Groups
|
||||
# - 82d40da2bc6923f41e14394075dd4b03 # No-RlsGroup
|
||||
# - e1a997ddb54e3ecbfe06341ad323c458 # Obfuscated
|
||||
# - 06d66ab109d4d2eddb2794d21526d140 # Retags
|
||||
# - 1b3994c551cbb92a2c781af061f4ab44 # Scene
|
||||
assign_scores_to:
|
||||
- name: WEB-1080p
|
||||
|
|
@ -1,152 +0,0 @@
|
|||
# yaml-language-server: $schema=https://schemas.recyclarr.dev/v8/config-schema.json
|
||||
# UHD Bluray + WEB profile (4K) — used when user chooses Ultra-HD
|
||||
# Template: recyclarr-ultra_hd.yml
|
||||
|
||||
radarr:
|
||||
radarr-instance:
|
||||
base_url: http://radarr:7878
|
||||
api_key: ${RADARR_API_KEY}
|
||||
|
||||
quality_definition:
|
||||
type: movie
|
||||
|
||||
quality_profiles:
|
||||
- trash_id: 64fb5f9858489bdac2af690e27c8f42f # UHD Bluray + WEB
|
||||
reset_unmatched_scores:
|
||||
enabled: true
|
||||
|
||||
custom_format_groups:
|
||||
add:
|
||||
- trash_id: ff204bbcecdd487d1cefcefdbf0c278d # [Optional] Golden Rule UHD
|
||||
select:
|
||||
- dc98083864ea246d05a42df0d05f81cc # x265 (HD)
|
||||
- 839bea857ed2c0a8e084f3cbdbd65ecb # x265 (no HDR/DV)
|
||||
- trash_id: a3ac6af01d78e4f21fcb75f601ac96df # [Unwanted] Unwanted Formats
|
||||
select:
|
||||
- b8cd450cbfa689c0259a01d9e29ba3d6 # 3D
|
||||
- cae4ca30163749b891686f95532519bd # AV1
|
||||
- b6832f586342ef70d9c128d40c07b872 # Bad Dual Groups
|
||||
- cc444569854e9de0b084ab2b8b1532b2 # Black and White Editions
|
||||
- ed38b889b31be83fda192888e2286d83 # BR-DISK
|
||||
- 0a3f082873eb454bde444150b70253cc # Extras
|
||||
- e6886871085226c3da1830830146846c # Generated Dynamic HDR
|
||||
- 90a6f9a284dff5103f6346090e6280c8 # LQ
|
||||
- e204b80c87be9497a8a6eaff48f72905 # LQ (Release Title)
|
||||
- 712d74cd88bceb883ee32f773656b1f5 # Sing-Along Versions
|
||||
- bfd8eb01832d646a0a89c4deb46f8564 # Upscaled
|
||||
|
||||
custom_formats:
|
||||
# Audio - Uncomment to enable Advanced Audio Formats
|
||||
- trash_ids:
|
||||
# - 496f355514737f7d83bf7aa4d24f8169 # TrueHD Atmos
|
||||
# - 2f22d89048b01681dde8afe203bf2e95 # DTS X
|
||||
# - 417804f7f2c4308c1f4c5d380d4c4475 # ATMOS (undefined)
|
||||
# - 1af239278386be2919e1bcee0bde047e # DD+ ATMOS
|
||||
# - 3cafb66171b47f226146a0770576870f # TrueHD
|
||||
# - dcf3ec6938fa32445f590a4da84256cd # DTS-HD MA
|
||||
# - a570d4a0e56a2874b64e5bfa55202a1b # FLAC
|
||||
# - e7c2fcae07cbada050a0af3357491d7b # PCM
|
||||
# - 8e109e50e0a0b83a5098b056e13bf6db # DTS-HD HRA
|
||||
# - 185f1dd7264c4562b9022d963ac37424 # DD+
|
||||
# - f9f847ac70a0af62ea4a08280b859636 # DTS-ES
|
||||
# - 1c1a4c5e823891c75bc50380a6866f73 # DTS
|
||||
# - 240770601cc226190c367ef59aba7463 # AAC
|
||||
# - c2998bd0d90ed5621d8df281e839436e # DD
|
||||
assign_scores_to:
|
||||
- name: UHD Bluray + WEB
|
||||
|
||||
# Movie Versions - Uncomment to prefer specific versions
|
||||
- trash_ids:
|
||||
# - 570bc9ebecd92723d2d21500f4be314c # Remaster
|
||||
# - eca37840c13c6ef2dd0262b141a5482f # 4K Remaster
|
||||
# - e0c07d59beb37348e975a930d5e50319 # Criterion Collection
|
||||
# - 9d27d9d2181838f76dee150882bdc58c # Masters of Cinema
|
||||
# - db9b4c4b53d312a3ca5f1378f6440fc9 # Vinegar Syndrome
|
||||
# - 957d0f44b592285f26449575e8b1167e # Special Edition
|
||||
# - eecf3a857724171f968a66cb5719e152 # IMAX
|
||||
# - 9f6cbff8cfe4ebbc1bde14c7b7bec0de # IMAX Enhanced
|
||||
assign_scores_to:
|
||||
- name: UHD Bluray + WEB
|
||||
|
||||
# Optional Unwanted
|
||||
- trash_ids:
|
||||
# - b6832f586342ef70d9c128d40c07b872 # Bad Dual Groups
|
||||
# - cc444569854e9de0b084ab2b8b1532b2 # Black and White Editions
|
||||
# - ae9b7c9ebde1f3bd336a8cbd1ec4c5e5 # No-RlsGroup
|
||||
# - 7357cf5161efbf8c4d5d0c30b4815ee2 # Obfuscated
|
||||
# - 5c44f52a8714fdd79bb4d98e2673be1f # Retags
|
||||
# - f537cf427b64c38c8e36298f657e4828 # Scene
|
||||
assign_scores_to:
|
||||
- name: UHD Bluray + WEB
|
||||
|
||||
# HDR/DV Preferences
|
||||
- trash_ids:
|
||||
# Uncomment to allow x265 HD releases with HDR/DV
|
||||
# - dc98083864ea246d05a42df0d05f81cc # x265 (HD)
|
||||
# assign_scores_to:
|
||||
# - name: UHD Bluray + WEB
|
||||
# score: 0
|
||||
# - trash_ids:
|
||||
# - 839bea857ed2c0a8e084f3cbdbd65ecb # x265 (no HDR/DV)
|
||||
assign_scores_to:
|
||||
- name: UHD Bluray + WEB
|
||||
|
||||
- trash_ids:
|
||||
# Comment out the next line if all your setups are fully DV compatible
|
||||
- 923b6abef9b17f937fab56cfcf89e1f1 # DV (w/o HDR fallback)
|
||||
|
||||
# HDR10+ Boost - Uncomment if you want to prefer HDR10+ releases
|
||||
# DV Boost - Uncomment if you want to prefer DV releases
|
||||
# Uncomment both if you want to prefer both (DV HDR10+)
|
||||
# - b337d6812e06c200ec9a2d3cfa9d20a7 # DV Boost
|
||||
# - caa37d0df9c348912df1fb1d88f9273a # HDR10+ Boost
|
||||
assign_scores_to:
|
||||
- name: UHD Bluray + WEB
|
||||
|
||||
# SDR Blocking - Only use ONE of the following
|
||||
- trash_ids:
|
||||
- 9c38ebb7384dada637be8899efa68e6f # SDR (block ALL SDR releases)
|
||||
# - 25c12f78430a3a23413652cbd1d48d77 # SDR (no WEBDL) - allow SDR WEB only
|
||||
assign_scores_to:
|
||||
- name: UHD Bluray + WEB
|
||||
|
||||
sonarr:
|
||||
sonarr-instance:
|
||||
base_url: http://sonarr:8989
|
||||
api_key: ${SONARR_API_KEY}
|
||||
|
||||
quality_definition:
|
||||
type: series
|
||||
|
||||
quality_profiles:
|
||||
- trash_id: a5ffae4bbda71217e132ce4ed37367c0 # WEB-1080p
|
||||
reset_unmatched_scores:
|
||||
enabled: true
|
||||
|
||||
custom_format_groups:
|
||||
add:
|
||||
- trash_id: 7a2ba4144a594826d4ac03515b371937 # [Optional] Streaming Services
|
||||
select_all: true
|
||||
|
||||
custom_formats:
|
||||
# Optional
|
||||
- trash_ids:
|
||||
# - 32b367365729d530ca1c124a0b180c64 # Bad Dual Groups
|
||||
# - 82d40da2bc6923f41e14394075dd4b03 # No-RlsGroup
|
||||
# - e1a997ddb54e3ecbfe06341ad323c458 # Obfuscated
|
||||
# - 06d66ab109d4d2eddb2794d21526d140 # Retags
|
||||
# - 1b3994c551cbb92a2c781af061f4ab44 # Scene
|
||||
assign_scores_to:
|
||||
- name: WEB-1080p
|
||||
|
||||
# x265 HD handling
|
||||
- trash_ids:
|
||||
# Uncomment to allow x265 HD releases with HDR/DV
|
||||
# - 47435ece6b99a0b477caf360e79ba0bb # x265 (HD)
|
||||
# assign_scores_to:
|
||||
# - name: WEB-1080p
|
||||
# score: 0
|
||||
# - trash_ids:
|
||||
# - 9b64dff695c2115facf1b6ea59c9bd07 # x265 (no HDR/DV)
|
||||
assign_scores_to:
|
||||
- name: WEB-1080p
|
||||
8
templates/recyclarr/includes/radarr-hd.yml
Normal file
8
templates/recyclarr/includes/radarr-hd.yml
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
# Include: Radarr 1080p profile (guide-backed HD Bluray + WEB)
|
||||
|
||||
quality_profiles:
|
||||
- trash_id: d1d67249d3890e49bc12e275d989a7e9 # HD Bluray + WEB
|
||||
name: assemblrr HD Bluray + WEB
|
||||
reset_unmatched_scores:
|
||||
enabled: true
|
||||
min_format_score: -1000
|
||||
14
templates/recyclarr/includes/radarr-soft-cfs.yml
Normal file
14
templates/recyclarr/includes/radarr-soft-cfs.yml
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
# Soften hard-block custom formats on assemblrr Radarr profiles
|
||||
|
||||
custom_formats:
|
||||
- trash_ids:
|
||||
- 90a6f9a284dff5103f6346090e6280c8 # LQ
|
||||
- e204b80c87be9497a8a6eaff48f72905 # LQ (Release Title)
|
||||
- dc98083864ea246d05a42df0d05f81cc # x265 (HD)
|
||||
- 839bea857ed2c0a8e084f3cbdbd65ecb # x265 (no HDR/DV)
|
||||
- b8cd450cbfa689c0259a01d9e29ba3d6 # 3D
|
||||
assign_scores_to:
|
||||
- name: assemblrr HD Bluray + WEB
|
||||
score: 0
|
||||
- name: assemblrr UHD Bluray + WEB
|
||||
score: 0
|
||||
8
templates/recyclarr/includes/radarr-uhd.yml
Normal file
8
templates/recyclarr/includes/radarr-uhd.yml
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
# Include: Radarr 4K profile (guide-backed UHD Bluray + WEB)
|
||||
|
||||
quality_profiles:
|
||||
- trash_id: 64fb5f9858489bdac2af690e27c8f42f # UHD Bluray + WEB
|
||||
name: assemblrr UHD Bluray + WEB
|
||||
reset_unmatched_scores:
|
||||
enabled: true
|
||||
min_format_score: -1000
|
||||
14
templates/recyclarr/includes/sonarr-soft-cfs.yml
Normal file
14
templates/recyclarr/includes/sonarr-soft-cfs.yml
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
# Soften hard-block custom formats on assemblrr Sonarr profiles
|
||||
|
||||
custom_formats:
|
||||
- trash_ids:
|
||||
- 9c11cd3f07101cdba90a2d81cf0e56b4 # LQ
|
||||
- e2315f990da2e2cbfc9fa5b7a6fcfe48 # LQ (Release Title)
|
||||
- 47435ece6b99a0b477caf360e79ba0bb # x265 (HD)
|
||||
- 9b64dff695c2115facf1b6ea59c9bd07 # x265 (no HDR/DV)
|
||||
- c9eafd50846d299b862ca9bb6ea91950 # x265
|
||||
assign_scores_to:
|
||||
- name: assemblrr WEB-1080p
|
||||
score: 0
|
||||
- name: assemblrr WEB-2160p
|
||||
score: 0
|
||||
8
templates/recyclarr/includes/sonarr-web-1080.yml
Normal file
8
templates/recyclarr/includes/sonarr-web-1080.yml
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
# Include: Sonarr 1080p profile (guide-backed WEB-1080p)
|
||||
|
||||
quality_profiles:
|
||||
- trash_id: 72dae194fc92bf828f32cde7744e51a1 # WEB-1080p
|
||||
name: assemblrr WEB-1080p
|
||||
reset_unmatched_scores:
|
||||
enabled: true
|
||||
min_format_score: -1000
|
||||
8
templates/recyclarr/includes/sonarr-web-2160.yml
Normal file
8
templates/recyclarr/includes/sonarr-web-2160.yml
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
# Include: Sonarr 4K profile (guide-backed WEB-2160p)
|
||||
|
||||
quality_profiles:
|
||||
- trash_id: d1498e7d189fbe6c7110ceaabb7473e6 # WEB-2160p
|
||||
name: assemblrr WEB-2160p
|
||||
reset_unmatched_scores:
|
||||
enabled: true
|
||||
min_format_score: -1000
|
||||
23
templates/recyclarr/recyclarr.yml
Normal file
23
templates/recyclarr/recyclarr.yml
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
# yaml-language-server: $schema=https://schemas.recyclarr.dev/v8/config-schema.json
|
||||
# Root: instance URLs/keys + include list. Profile packs are under includes/.
|
||||
# All packs listed here are synced; Seerr's default is chosen at setup.
|
||||
# See README "Quality Profiles & TRaSH Guides".
|
||||
|
||||
radarr:
|
||||
radarr-instance:
|
||||
base_url: http://radarr:7878
|
||||
api_key: ${RADARR_API_KEY}
|
||||
# No quality_definition → no min/max size filters from Recyclarr.
|
||||
include:
|
||||
- config: radarr-hd.yml
|
||||
- config: radarr-uhd.yml
|
||||
- config: radarr-soft-cfs.yml
|
||||
|
||||
sonarr:
|
||||
sonarr-instance:
|
||||
base_url: http://sonarr:8989
|
||||
api_key: ${SONARR_API_KEY}
|
||||
include:
|
||||
- config: sonarr-web-1080.yml
|
||||
- config: sonarr-web-2160.yml
|
||||
- config: sonarr-soft-cfs.yml
|
||||
|
|
@ -7,7 +7,7 @@ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|||
# shellcheck disable=SC1091
|
||||
source "$SCRIPT_DIR/../helpers.sh"
|
||||
|
||||
# Ubuntu 22.04 desktop infohash + public trackers
|
||||
# Ubuntu 22.04 desktop infohash (official FOSS image)
|
||||
TARGET_HASH="3b245504cf5f11bbdbe1201cea6a6bf45aee1bc0"
|
||||
MAGNET="magnet:?xt=urn:btih:${TARGET_HASH}&dn=ubuntu-22.04.4-desktop-amd64.iso&tr=udp%3A%2F%2Ftracker.opentrackr.org%3A1337%2Fannounce&tr=udp%3A%2F%2Ftracker.openbittorrent.com%3A6969%2Fannounce"
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue