diff --git a/plex/scan-plex-libraries.sh b/plex/scan-plex-libraries.sh index 2a8fe97..7e0ac1e 100755 --- a/plex/scan-plex-libraries.sh +++ b/plex/scan-plex-libraries.sh @@ -57,6 +57,8 @@ readonly RESET='\033[0m' # 🔧 Configuration readonly PLEX_SERVICE="plexmediaserver" +readonly PLEX_PREFS="/var/lib/plexmediaserver/Library/Application Support/Plex Media Server/Preferences.xml" +readonly PLEX_API_BASE="http://localhost:32400" readonly SCRIPT_NAME="$(basename "$0")" readonly SCRIPT_DIR="$(dirname "$(readlink -f "$0")")" readonly LOG_DIR="${SCRIPT_DIR}/../logs" @@ -144,6 +146,55 @@ find_scanner() { return 1 } +# 🚀 Run Plex Media Scanner as the plex user with correct environment +# Usage: run_scanner [args...] — runs and returns exit code +run_scanner() { + sudo -u plex \ + env LD_LIBRARY_PATH=/usr/lib/plexmediaserver \ + PLEX_MEDIA_SERVER_APPLICATION_SUPPORT_DIR="/var/lib/plexmediaserver/Library/Application Support" \ + "$SCANNER_PATH" "$@" +} + +# 🔑 Get Plex authentication token from Preferences.xml +get_plex_token() { + local token + token=$(sudo grep -oP 'PlexOnlineToken="\K[^"]+' "$PLEX_PREFS" 2>/dev/null) + if [[ -z "$token" ]]; then + log_verbose "Could not read Plex token from Preferences.xml" + return 1 + fi + echo "$token" +} + +# 📡 List library sections via the Plex API +# Output format: "key|title|type" per line (e.g. "1|Movies|movie") +api_list_sections() { + local token + if ! token=$(get_plex_token); then + return 1 + fi + + local xml + if ! xml=$(curl -fsS "${PLEX_API_BASE}/library/sections?X-Plex-Token=${token}" 2>/dev/null); then + log_verbose "Plex API request failed" + return 1 + fi + + # Parse XML: extract key, title, and type from elements + echo "$xml" | grep -oP ']*>' | while IFS= read -r tag; do + local key title type + key=$(echo "$tag" | grep -oP 'key="\K[^"]+') + title=$(echo "$tag" | grep -oP 'title="\K[^"]+') + type=$(echo "$tag" | grep -oP 'type="\K[^"]+') + echo "${key}|${title}|${type}" + done +} + +# 📋 Get just the section IDs from the API (one per line) +api_list_section_ids() { + api_list_sections | cut -d'|' -f1 +} + # 🏥 Function to check Plex service status check_plex_service() { log_verbose "Checking Plex service status..." @@ -166,38 +217,24 @@ list_libraries() { return 2 fi - if ! find_scanner; then - return 3 - fi - - # Set library path for Linux - export LD_LIBRARY_PATH=/usr/lib/plexmediaserver:${LD_LIBRARY_PATH:-} - - local output - if output=$("$SCANNER_PATH" --list 2>&1); then - echo "" - echo -e "${BOLD}${CYAN}Available Library Sections:${RESET}" - echo -e "${DIM}${CYAN}=========================${RESET}" - - # Parse and format the output - echo "$output" | while IFS= read -r line; do - if [[ "$line" =~ ^[[:space:]]*([0-9]+):[[:space:]]*(.+)$ ]]; then - local section_id="${BASH_REMATCH[1]}" - local section_name="${BASH_REMATCH[2]}" - echo -e "${GREEN}${BOLD} ${section_id}:${RESET} ${WHITE}${section_name}${RESET}" - elif [[ -n "$line" ]]; then - echo -e "${DIM} $line${RESET}" - fi - done - - echo "" - print_status "${CHECKMARK}" "Library listing completed" "${GREEN}" - return 0 - else - print_status "${CROSS}" "Failed to list libraries" "${RED}" - echo -e "${DIM}${RED}Error output: $output${RESET}" + local sections + if ! sections=$(api_list_sections) || [[ -z "$sections" ]]; then + print_status "${CROSS}" "Failed to retrieve library sections from Plex API" "${RED}" return 5 fi + + echo "" + echo -e "${BOLD}${CYAN}Available Library Sections:${RESET}" + echo -e "${DIM}${CYAN}=========================${RESET}" + + while IFS='|' read -r key title type; do + [[ -n "$key" ]] || continue + printf " ${GREEN}${BOLD}%-4s${RESET} ${WHITE}%-30s${RESET} ${DIM}(%s)${RESET}\n" "${key}:" "$title" "$type" + done <<< "$sections" + + echo "" + print_status "${CHECKMARK}" "Library listing completed" "${GREEN}" + return 0 } # 🔍 Function to validate section ID @@ -209,10 +246,9 @@ validate_section_id() { return 1 fi - # Get list of valid section IDs - export LD_LIBRARY_PATH=/usr/lib/plexmediaserver:${LD_LIBRARY_PATH:-} + # Get list of valid section IDs via API local valid_ids - if valid_ids=$("$SCANNER_PATH" --list 2>/dev/null | grep -oE '^[[:space:]]*[0-9]+:' | grep -oE '[0-9]+'); then + if valid_ids=$(api_list_section_ids) && [[ -n "$valid_ids" ]]; then if echo "$valid_ids" | grep -q "^${section_id}$"; then return 0 else @@ -237,9 +273,7 @@ scan_library() { return 4 fi - export LD_LIBRARY_PATH=/usr/lib/plexmediaserver:${LD_LIBRARY_PATH:-} - - if "$SCANNER_PATH" --scan --section "$section_id" ${VERBOSE:+--verbose}; then + if run_scanner --scan --section "$section_id" ${VERBOSE:+--verbose}; then print_status "${CHECKMARK}" "Library section $section_id scan completed" "${GREEN}" return 0 else @@ -250,16 +284,15 @@ scan_library() { print_status "${ROCKET}" "Scanning all libraries for new media..." "${BLUE}" # Get all section IDs and scan each one - export LD_LIBRARY_PATH=/usr/lib/plexmediaserver:${LD_LIBRARY_PATH:-} local section_ids - if section_ids=$("$SCANNER_PATH" --list 2>/dev/null | grep -oE '^[[:space:]]*[0-9]+:' | grep -oE '[0-9]+'); then + if section_ids=$(api_list_section_ids) && [[ -n "$section_ids" ]]; then local failed_sections=() while IFS= read -r id; do [[ -n "$id" ]] || continue print_status "${INFO}" "Scanning section $id..." "${YELLOW}" - if "$SCANNER_PATH" --scan --section "$id" ${VERBOSE:+--verbose}; then + if run_scanner --scan --section "$id" ${VERBOSE:+--verbose}; then print_status "${CHECKMARK}" "Section $id scanned successfully" "${GREEN}" else print_status "${CROSS}" "Failed to scan section $id" "${RED}" @@ -298,9 +331,7 @@ refresh_library() { return 4 fi - export LD_LIBRARY_PATH=/usr/lib/plexmediaserver:${LD_LIBRARY_PATH:-} - - if "$SCANNER_PATH" --refresh $force_flag --section "$section_id" ${VERBOSE:+--verbose}; then + if run_scanner --refresh $force_flag --section "$section_id" ${VERBOSE:+--verbose}; then print_status "${CHECKMARK}" "Library section $section_id metadata refreshed" "${GREEN}" return 0 else @@ -311,16 +342,15 @@ refresh_library() { print_status "${RECYCLE}" "Refreshing metadata for all libraries..." "${BLUE}" # Get all section IDs and refresh each one - export LD_LIBRARY_PATH=/usr/lib/plexmediaserver:${LD_LIBRARY_PATH:-} local section_ids - if section_ids=$("$SCANNER_PATH" --list 2>/dev/null | grep -oE '^[[:space:]]*[0-9]+:' | grep -oE '[0-9]+'); then + if section_ids=$(api_list_section_ids) && [[ -n "$section_ids" ]]; then local failed_sections=() while IFS= read -r id; do [[ -n "$id" ]] || continue print_status "${INFO}" "Refreshing section $id..." "${YELLOW}" - if "$SCANNER_PATH" --refresh $force_flag --section "$id" ${VERBOSE:+--verbose}; then + if run_scanner --refresh $force_flag --section "$id" ${VERBOSE:+--verbose}; then print_status "${CHECKMARK}" "Section $id refreshed successfully" "${GREEN}" else print_status "${CROSS}" "Failed to refresh section $id" "${RED}" @@ -359,9 +389,7 @@ analyze_library() { return 4 fi - export LD_LIBRARY_PATH=/usr/lib/plexmediaserver:${LD_LIBRARY_PATH:-} - - if "$SCANNER_PATH" $analyze_flag --section "$section_id" ${VERBOSE:+--verbose}; then + if run_scanner $analyze_flag --section "$section_id" ${VERBOSE:+--verbose}; then print_status "${CHECKMARK}" "Library section $section_id analysis completed" "${GREEN}" return 0 else @@ -372,16 +400,15 @@ analyze_library() { print_status "${SEARCH}" "Analyzing media in all libraries..." "${BLUE}" # Get all section IDs and analyze each one - export LD_LIBRARY_PATH=/usr/lib/plexmediaserver:${LD_LIBRARY_PATH:-} local section_ids - if section_ids=$("$SCANNER_PATH" --list 2>/dev/null | grep -oE '^[[:space:]]*[0-9]+:' | grep -oE '[0-9]+'); then + if section_ids=$(api_list_section_ids) && [[ -n "$section_ids" ]]; then local failed_sections=() while IFS= read -r id; do [[ -n "$id" ]] || continue print_status "${INFO}" "Analyzing section $id..." "${YELLOW}" - if "$SCANNER_PATH" $analyze_flag --section "$id" ${VERBOSE:+--verbose}; then + if run_scanner $analyze_flag --section "$id" ${VERBOSE:+--verbose}; then print_status "${CHECKMARK}" "Section $id analyzed successfully" "${GREEN}" else print_status "${CROSS}" "Failed to analyze section $id" "${RED}" @@ -414,9 +441,7 @@ generate_thumbnails() { return 4 fi - export LD_LIBRARY_PATH=/usr/lib/plexmediaserver:${LD_LIBRARY_PATH:-} - - if "$SCANNER_PATH" --generate --section "$section_id" ${VERBOSE:+--verbose}; then + if run_scanner --generate --section "$section_id" ${VERBOSE:+--verbose}; then print_status "${CHECKMARK}" "Thumbnails generated for library section $section_id" "${GREEN}" return 0 else @@ -427,16 +452,15 @@ generate_thumbnails() { print_status "${SPARKLES}" "Generating thumbnails for all libraries..." "${BLUE}" # Get all section IDs and generate thumbnails for each one - export LD_LIBRARY_PATH=/usr/lib/plexmediaserver:${LD_LIBRARY_PATH:-} local section_ids - if section_ids=$("$SCANNER_PATH" --list 2>/dev/null | grep -oE '^[[:space:]]*[0-9]+:' | grep -oE '[0-9]+'); then + if section_ids=$(api_list_section_ids) && [[ -n "$section_ids" ]]; then local failed_sections=() while IFS= read -r id; do [[ -n "$id" ]] || continue print_status "${INFO}" "Generating thumbnails for section $id..." "${YELLOW}" - if "$SCANNER_PATH" --generate --section "$id" ${VERBOSE:+--verbose}; then + if run_scanner --generate --section "$id" ${VERBOSE:+--verbose}; then print_status "${CHECKMARK}" "Section $id thumbnails generated successfully" "${GREEN}" else print_status "${CROSS}" "Failed to generate thumbnails for section $id" "${RED}" @@ -473,9 +497,7 @@ show_library_tree() { return 4 fi - export LD_LIBRARY_PATH=/usr/lib/plexmediaserver:${LD_LIBRARY_PATH:-} - - if "$SCANNER_PATH" --tree --section "$section_id"; then + if run_scanner --tree --section "$section_id"; then print_status "${CHECKMARK}" "Tree display completed for library section $section_id" "${GREEN}" return 0 else