mirror of
https://github.com/acedanger/shell.git
synced 2025-12-06 08:50:12 -08:00
771 lines
27 KiB
Bash
Executable File
771 lines
27 KiB
Bash
Executable File
#!/bin/bash
|
|
|
|
################################################################################
|
|
# Plex Library Scanner Script
|
|
################################################################################
|
|
#
|
|
# Author: Peter Wood <peter@peterwood.dev>
|
|
# Description: Command-line interface for Plex Media Scanner operations.
|
|
# Provides library scanning, metadata refresh, and analysis
|
|
# capabilities with styled output and error handling.
|
|
#
|
|
# Features:
|
|
# - List all Plex libraries with section IDs
|
|
# - Scan specific libraries or all libraries for new media
|
|
# - Force refresh metadata for libraries
|
|
# - Deep analysis of media files
|
|
# - Generate thumbnails and preview images
|
|
# - Interactive mode for easy library management
|
|
# - Comprehensive error handling and validation
|
|
#
|
|
# Usage:
|
|
# ./scan-plex-libraries.sh list # List all libraries
|
|
# ./scan-plex-libraries.sh scan [section_id] # Scan library (all if no ID)
|
|
# ./scan-plex-libraries.sh refresh [section_id] # Refresh library metadata
|
|
# ./scan-plex-libraries.sh analyze [section_id] # Analyze library media
|
|
# ./scan-plex-libraries.sh generate [section_id] # Generate thumbnails
|
|
# ./scan-plex-libraries.sh # Interactive mode
|
|
#
|
|
# Dependencies:
|
|
# - Plex Media Server
|
|
# - Plex Media Scanner binary
|
|
# - systemctl (for service management)
|
|
#
|
|
# Exit Codes:
|
|
# 0 - Success
|
|
# 1 - General error
|
|
# 2 - Plex service not running
|
|
# 3 - Scanner binary not found
|
|
# 4 - Invalid section ID
|
|
# 5 - Scanner operation failed
|
|
#
|
|
################################################################################
|
|
|
|
set -euo pipefail
|
|
|
|
# 🎨 Color definitions for styled output
|
|
readonly RED='\033[0;31m'
|
|
readonly GREEN='\033[0;32m'
|
|
readonly YELLOW='\033[1;33m'
|
|
readonly BLUE='\033[0;34m'
|
|
readonly PURPLE='\033[0;35m'
|
|
readonly CYAN='\033[0;36m'
|
|
readonly WHITE='\033[1;37m'
|
|
readonly BOLD='\033[1m'
|
|
readonly DIM='\033[2m'
|
|
readonly RESET='\033[0m'
|
|
|
|
# 🔧 Configuration
|
|
readonly PLEX_SERVICE="plexmediaserver"
|
|
readonly SCRIPT_NAME="$(basename "$0")"
|
|
readonly SCRIPT_DIR="$(dirname "$(readlink -f "$0")")"
|
|
readonly LOG_DIR="${SCRIPT_DIR}/../logs"
|
|
readonly LOG_FILE="${LOG_DIR}/plex-scanner.log"
|
|
|
|
# Plex Media Scanner paths (common locations)
|
|
readonly SCANNER_PATHS=(
|
|
"/usr/lib/plexmediaserver/Plex Media Scanner"
|
|
"/opt/plex/Plex Media Scanner"
|
|
"/usr/local/plex/Plex Media Scanner"
|
|
"/Applications/Plex Media Server.app/Contents/MacOS/Plex Media Scanner"
|
|
)
|
|
|
|
# 🎭 ASCII symbols for compatible output
|
|
readonly CHECKMARK="[✓]"
|
|
readonly CROSS="[✗]"
|
|
readonly ROCKET="[>]"
|
|
readonly STOP_SIGN="[■]"
|
|
readonly RECYCLE="[~]"
|
|
readonly INFO="[i]"
|
|
readonly HOURGLASS="[*]"
|
|
readonly SPARKLES="[*]"
|
|
readonly SEARCH="[?]"
|
|
readonly LIBRARY="[📚]"
|
|
|
|
# Global variables
|
|
SCANNER_PATH=""
|
|
VERBOSE=false
|
|
|
|
# 🎉 Function to print completion footer
|
|
print_footer() {
|
|
echo -e "\n${DIM}${CYAN}--- Operation completed ${SPARKLES} ---${RESET}\n"
|
|
}
|
|
|
|
# 🎯 Function to print status with style
|
|
print_status() {
|
|
local status="$1"
|
|
local message="$2"
|
|
local color="$3"
|
|
echo -e "${color}${BOLD}[${status}]${RESET} ${message}"
|
|
|
|
# Log to file if log directory exists
|
|
if [[ -d "$LOG_DIR" ]]; then
|
|
echo "$(date '+%Y-%m-%d %H:%M:%S') - [${status}] ${message}" >> "$LOG_FILE"
|
|
fi
|
|
}
|
|
|
|
# 📝 Function to log verbose output
|
|
log_verbose() {
|
|
local message="$1"
|
|
if [[ "$VERBOSE" == true ]]; then
|
|
echo -e "${DIM}${CYAN}[DEBUG]${RESET} ${message}"
|
|
fi
|
|
|
|
# Always log to file if available
|
|
if [[ -d "$LOG_DIR" ]]; then
|
|
echo "$(date '+%Y-%m-%d %H:%M:%S') - [DEBUG] ${message}" >> "$LOG_FILE"
|
|
fi
|
|
}
|
|
|
|
# 🔍 Function to find Plex Media Scanner binary
|
|
find_scanner() {
|
|
log_verbose "Searching for Plex Media Scanner binary..."
|
|
|
|
for path in "${SCANNER_PATHS[@]}"; do
|
|
if [[ -f "$path" && -x "$path" ]]; then
|
|
SCANNER_PATH="$path"
|
|
log_verbose "Found scanner at: $path"
|
|
return 0
|
|
fi
|
|
done
|
|
|
|
# Try to find it in PATH
|
|
if command -v "Plex Media Scanner" >/dev/null 2>&1; then
|
|
SCANNER_PATH="Plex Media Scanner"
|
|
log_verbose "Found scanner in PATH"
|
|
return 0
|
|
fi
|
|
|
|
print_status "${CROSS}" "Plex Media Scanner binary not found!" "${RED}"
|
|
print_status "${INFO}" "Checked locations:" "${YELLOW}"
|
|
for path in "${SCANNER_PATHS[@]}"; do
|
|
echo -e " ${DIM}${YELLOW}• $path${RESET}"
|
|
done
|
|
return 1
|
|
}
|
|
|
|
# 🏥 Function to check Plex service status
|
|
check_plex_service() {
|
|
log_verbose "Checking Plex service status..."
|
|
|
|
if ! systemctl is-active --quiet "$PLEX_SERVICE"; then
|
|
print_status "${CROSS}" "Plex Media Server is not running!" "${RED}"
|
|
print_status "${INFO}" "Start Plex with: ${BOLD}sudo systemctl start $PLEX_SERVICE${RESET}" "${YELLOW}"
|
|
return 1
|
|
fi
|
|
|
|
log_verbose "Plex service is running"
|
|
return 0
|
|
}
|
|
|
|
# 📚 Function to list all library sections
|
|
list_libraries() {
|
|
print_status "${LIBRARY}" "Listing all Plex library sections..." "${BLUE}"
|
|
|
|
if ! check_plex_service; then
|
|
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}"
|
|
return 5
|
|
fi
|
|
}
|
|
|
|
# 🔍 Function to validate section ID
|
|
validate_section_id() {
|
|
local section_id="$1"
|
|
|
|
if [[ ! "$section_id" =~ ^[0-9]+$ ]]; then
|
|
print_status "${CROSS}" "Invalid section ID: $section_id (must be a number)" "${RED}"
|
|
return 1
|
|
fi
|
|
|
|
# Get list of valid section IDs
|
|
export LD_LIBRARY_PATH=/usr/lib/plexmediaserver:${LD_LIBRARY_PATH:-}
|
|
local valid_ids
|
|
if valid_ids=$("$SCANNER_PATH" --list 2>/dev/null | grep -oE '^[[:space:]]*[0-9]+:' | grep -oE '[0-9]+'); then
|
|
if echo "$valid_ids" | grep -q "^${section_id}$"; then
|
|
return 0
|
|
else
|
|
print_status "${CROSS}" "Section ID $section_id not found" "${RED}"
|
|
print_status "${INFO}" "Valid section IDs: $(echo "$valid_ids" | tr '\n' ' ')" "${YELLOW}"
|
|
return 1
|
|
fi
|
|
else
|
|
print_status "${CROSS}" "Unable to validate section ID" "${RED}"
|
|
return 1
|
|
fi
|
|
}
|
|
|
|
# 🔄 Function to scan library for new media
|
|
scan_library() {
|
|
local section_id="$1"
|
|
|
|
if [[ -n "$section_id" ]]; then
|
|
print_status "${ROCKET}" "Scanning library section $section_id for new media..." "${BLUE}"
|
|
|
|
if ! validate_section_id "$section_id"; then
|
|
return 4
|
|
fi
|
|
|
|
export LD_LIBRARY_PATH=/usr/lib/plexmediaserver:${LD_LIBRARY_PATH:-}
|
|
|
|
if "$SCANNER_PATH" --scan --section "$section_id" ${VERBOSE:+--verbose}; then
|
|
print_status "${CHECKMARK}" "Library section $section_id scan completed" "${GREEN}"
|
|
return 0
|
|
else
|
|
print_status "${CROSS}" "Failed to scan library section $section_id" "${RED}"
|
|
return 5
|
|
fi
|
|
else
|
|
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
|
|
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
|
|
print_status "${CHECKMARK}" "Section $id scanned successfully" "${GREEN}"
|
|
else
|
|
print_status "${CROSS}" "Failed to scan section $id" "${RED}"
|
|
failed_sections+=("$id")
|
|
fi
|
|
done <<< "$section_ids"
|
|
|
|
if [[ ${#failed_sections[@]} -eq 0 ]]; then
|
|
print_status "${CHECKMARK}" "All libraries scanned successfully" "${GREEN}"
|
|
return 0
|
|
else
|
|
print_status "${CROSS}" "Some libraries failed to scan: ${failed_sections[*]}" "${RED}"
|
|
return 5
|
|
fi
|
|
else
|
|
print_status "${CROSS}" "Unable to retrieve library list" "${RED}"
|
|
return 5
|
|
fi
|
|
fi
|
|
}
|
|
|
|
# 🔄 Function to refresh library metadata
|
|
refresh_library() {
|
|
local section_id="$1"
|
|
local force="${2:-false}"
|
|
|
|
local force_flag=""
|
|
if [[ "$force" == "true" ]]; then
|
|
force_flag="--force"
|
|
fi
|
|
|
|
if [[ -n "$section_id" ]]; then
|
|
print_status "${RECYCLE}" "Refreshing metadata for library section $section_id..." "${BLUE}"
|
|
|
|
if ! validate_section_id "$section_id"; then
|
|
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
|
|
print_status "${CHECKMARK}" "Library section $section_id metadata refreshed" "${GREEN}"
|
|
return 0
|
|
else
|
|
print_status "${CROSS}" "Failed to refresh library section $section_id" "${RED}"
|
|
return 5
|
|
fi
|
|
else
|
|
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
|
|
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
|
|
print_status "${CHECKMARK}" "Section $id refreshed successfully" "${GREEN}"
|
|
else
|
|
print_status "${CROSS}" "Failed to refresh section $id" "${RED}"
|
|
failed_sections+=("$id")
|
|
fi
|
|
done <<< "$section_ids"
|
|
|
|
if [[ ${#failed_sections[@]} -eq 0 ]]; then
|
|
print_status "${CHECKMARK}" "All libraries refreshed successfully" "${GREEN}"
|
|
return 0
|
|
else
|
|
print_status "${CROSS}" "Some libraries failed to refresh: ${failed_sections[*]}" "${RED}"
|
|
return 5
|
|
fi
|
|
else
|
|
print_status "${CROSS}" "Unable to retrieve library list" "${RED}"
|
|
return 5
|
|
fi
|
|
fi
|
|
}
|
|
|
|
# 🔬 Function to analyze library media
|
|
analyze_library() {
|
|
local section_id="$1"
|
|
local deep="${2:-false}"
|
|
|
|
local analyze_flag="--analyze"
|
|
if [[ "$deep" == "true" ]]; then
|
|
analyze_flag="--analyze-deeply"
|
|
fi
|
|
|
|
if [[ -n "$section_id" ]]; then
|
|
print_status "${SEARCH}" "Analyzing media in library section $section_id..." "${BLUE}"
|
|
|
|
if ! validate_section_id "$section_id"; then
|
|
return 4
|
|
fi
|
|
|
|
export LD_LIBRARY_PATH=/usr/lib/plexmediaserver:${LD_LIBRARY_PATH:-}
|
|
|
|
if "$SCANNER_PATH" $analyze_flag --section "$section_id" ${VERBOSE:+--verbose}; then
|
|
print_status "${CHECKMARK}" "Library section $section_id analysis completed" "${GREEN}"
|
|
return 0
|
|
else
|
|
print_status "${CROSS}" "Failed to analyze library section $section_id" "${RED}"
|
|
return 5
|
|
fi
|
|
else
|
|
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
|
|
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
|
|
print_status "${CHECKMARK}" "Section $id analyzed successfully" "${GREEN}"
|
|
else
|
|
print_status "${CROSS}" "Failed to analyze section $id" "${RED}"
|
|
failed_sections+=("$id")
|
|
fi
|
|
done <<< "$section_ids"
|
|
|
|
if [[ ${#failed_sections[@]} -eq 0 ]]; then
|
|
print_status "${CHECKMARK}" "All libraries analyzed successfully" "${GREEN}"
|
|
return 0
|
|
else
|
|
print_status "${CROSS}" "Some libraries failed to analyze: ${failed_sections[*]}" "${RED}"
|
|
return 5
|
|
fi
|
|
else
|
|
print_status "${CROSS}" "Unable to retrieve library list" "${RED}"
|
|
return 5
|
|
fi
|
|
fi
|
|
}
|
|
|
|
# 🖼️ Function to generate thumbnails and fanart
|
|
generate_thumbnails() {
|
|
local section_id="$1"
|
|
|
|
if [[ -n "$section_id" ]]; then
|
|
print_status "${SPARKLES}" "Generating thumbnails for library section $section_id..." "${BLUE}"
|
|
|
|
if ! validate_section_id "$section_id"; then
|
|
return 4
|
|
fi
|
|
|
|
export LD_LIBRARY_PATH=/usr/lib/plexmediaserver:${LD_LIBRARY_PATH:-}
|
|
|
|
if "$SCANNER_PATH" --generate --section "$section_id" ${VERBOSE:+--verbose}; then
|
|
print_status "${CHECKMARK}" "Thumbnails generated for library section $section_id" "${GREEN}"
|
|
return 0
|
|
else
|
|
print_status "${CROSS}" "Failed to generate thumbnails for library section $section_id" "${RED}"
|
|
return 5
|
|
fi
|
|
else
|
|
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
|
|
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
|
|
print_status "${CHECKMARK}" "Section $id thumbnails generated successfully" "${GREEN}"
|
|
else
|
|
print_status "${CROSS}" "Failed to generate thumbnails for section $id" "${RED}"
|
|
failed_sections+=("$id")
|
|
fi
|
|
done <<< "$section_ids"
|
|
|
|
if [[ ${#failed_sections[@]} -eq 0 ]]; then
|
|
print_status "${CHECKMARK}" "Thumbnails generated for all libraries" "${GREEN}"
|
|
return 0
|
|
else
|
|
print_status "${CROSS}" "Some libraries failed thumbnail generation: ${failed_sections[*]}" "${RED}"
|
|
return 5
|
|
fi
|
|
else
|
|
print_status "${CROSS}" "Unable to retrieve library list" "${RED}"
|
|
return 5
|
|
fi
|
|
fi
|
|
}
|
|
|
|
# 🌳 Function to show library tree structure
|
|
show_library_tree() {
|
|
local section_id="$1"
|
|
|
|
if [[ -z "$section_id" ]]; then
|
|
print_status "${CROSS}" "Section ID required for tree display" "${RED}"
|
|
return 1
|
|
fi
|
|
|
|
print_status "${LIBRARY}" "Showing tree structure for library section $section_id..." "${BLUE}"
|
|
|
|
if ! validate_section_id "$section_id"; then
|
|
return 4
|
|
fi
|
|
|
|
export LD_LIBRARY_PATH=/usr/lib/plexmediaserver:${LD_LIBRARY_PATH:-}
|
|
|
|
if "$SCANNER_PATH" --tree --section "$section_id"; then
|
|
print_status "${CHECKMARK}" "Tree display completed for library section $section_id" "${GREEN}"
|
|
return 0
|
|
else
|
|
print_status "${CROSS}" "Failed to display tree for library section $section_id" "${RED}"
|
|
return 5
|
|
fi
|
|
}
|
|
|
|
# ❓ Function to show help
|
|
show_help() {
|
|
echo -e "${BOLD}${CYAN}Plex Library Scanner${RESET}"
|
|
echo -e "${DIM}Modern command-line interface for Plex Media Scanner${RESET}"
|
|
echo ""
|
|
echo -e "${BOLD}Usage:${RESET}"
|
|
echo -e " ${SCRIPT_NAME} ${GREEN}list${RESET} ${DIM}# List all library sections${RESET}"
|
|
echo -e " ${SCRIPT_NAME} ${GREEN}scan${RESET} [section_id] ${DIM}# Scan for new media (all if no ID)${RESET}"
|
|
echo -e " ${SCRIPT_NAME} ${GREEN}refresh${RESET} [section_id] [force] ${DIM}# Refresh metadata (force=true for forced refresh)${RESET}"
|
|
echo -e " ${SCRIPT_NAME} ${GREEN}analyze${RESET} [section_id] [deep] ${DIM}# Analyze media (deep=true for deep analysis)${RESET}"
|
|
echo -e " ${SCRIPT_NAME} ${GREEN}generate${RESET} [section_id] ${DIM}# Generate thumbnails and fanart${RESET}"
|
|
echo -e " ${SCRIPT_NAME} ${GREEN}tree${RESET} <section_id> ${DIM}# Show library tree structure${RESET}"
|
|
echo -e " ${SCRIPT_NAME} ${GREEN}interactive${RESET} ${DIM}# Interactive mode${RESET}"
|
|
echo ""
|
|
echo -e "${BOLD}Options:${RESET}"
|
|
echo -e " ${GREEN}-v, --verbose${RESET} ${DIM}# Enable verbose output${RESET}"
|
|
echo -e " ${GREEN}-h, --help${RESET} ${DIM}# Show this help message${RESET}"
|
|
echo ""
|
|
echo -e "${BOLD}Examples:${RESET}"
|
|
echo -e " ${DIM}# List all libraries${RESET}"
|
|
echo -e " ${SCRIPT_NAME} list"
|
|
echo ""
|
|
echo -e " ${DIM}# Scan all libraries for new media${RESET}"
|
|
echo -e " ${SCRIPT_NAME} scan"
|
|
echo ""
|
|
echo -e " ${DIM}# Scan specific library (ID 29)${RESET}"
|
|
echo -e " ${SCRIPT_NAME} scan 29"
|
|
echo ""
|
|
echo -e " ${DIM}# Force refresh all libraries${RESET}"
|
|
echo -e " ${SCRIPT_NAME} refresh \"\" true"
|
|
echo ""
|
|
echo -e " ${DIM}# Deep analyze specific library${RESET}"
|
|
echo -e " ${SCRIPT_NAME} analyze 29 true"
|
|
echo ""
|
|
echo -e "${BOLD}Notes:${RESET}"
|
|
echo -e " ${DIM}• Requires Plex Media Server to be running${RESET}"
|
|
echo -e " ${DIM}• Operations may take considerable time for large libraries${RESET}"
|
|
echo -e " ${DIM}• Use verbose mode (-v) for detailed progress information${RESET}"
|
|
echo -e " ${DIM}• Log files are written to: ${LOG_FILE}${RESET}"
|
|
}
|
|
|
|
# 🎯 Interactive mode function
|
|
interactive_mode() {
|
|
echo -e "${BOLD}${CYAN}🎬 Plex Library Scanner - Interactive Mode${RESET}"
|
|
echo -e "${DIM}Select an operation to perform:${RESET}"
|
|
echo ""
|
|
|
|
# First, check if Plex is running and scanner is available
|
|
if ! check_plex_service; then
|
|
return 2
|
|
fi
|
|
|
|
if ! find_scanner; then
|
|
return 3
|
|
fi
|
|
|
|
while true; do
|
|
echo -e "${BOLD}Available Operations:${RESET}"
|
|
echo -e "${GREEN}1)${RESET} List all libraries"
|
|
echo -e "${GREEN}2)${RESET} Scan libraries for new media"
|
|
echo -e "${GREEN}3)${RESET} Refresh library metadata"
|
|
echo -e "${GREEN}4)${RESET} Analyze library media"
|
|
echo -e "${GREEN}5)${RESET} Generate thumbnails"
|
|
echo -e "${GREEN}6)${RESET} Show library tree"
|
|
echo -e "${GREEN}q)${RESET} Quit"
|
|
echo ""
|
|
|
|
read -p "$(echo -e "${BOLD}Choose an option [1-6,q]:${RESET} ")" choice
|
|
|
|
case "$choice" in
|
|
1)
|
|
echo ""
|
|
list_libraries
|
|
;;
|
|
2)
|
|
echo ""
|
|
echo -e "${BOLD}Scan Options:${RESET}"
|
|
echo -e "${GREEN}1)${RESET} Scan all libraries"
|
|
echo -e "${GREEN}2)${RESET} Scan specific library"
|
|
read -p "$(echo -e "${BOLD}Choose [1-2]:${RESET} ")" scan_choice
|
|
|
|
case "$scan_choice" in
|
|
1)
|
|
scan_library ""
|
|
;;
|
|
2)
|
|
read -p "$(echo -e "${BOLD}Enter section ID:${RESET} ")" section_id
|
|
scan_library "$section_id"
|
|
;;
|
|
*)
|
|
print_status "${CROSS}" "Invalid choice" "${RED}"
|
|
;;
|
|
esac
|
|
;;
|
|
3)
|
|
echo ""
|
|
echo -e "${BOLD}Refresh Options:${RESET}"
|
|
echo -e "${GREEN}1)${RESET} Refresh all libraries"
|
|
echo -e "${GREEN}2)${RESET} Refresh specific library"
|
|
echo -e "${GREEN}3)${RESET} Force refresh all libraries"
|
|
echo -e "${GREEN}4)${RESET} Force refresh specific library"
|
|
read -p "$(echo -e "${BOLD}Choose [1-4]:${RESET} ")" refresh_choice
|
|
|
|
case "$refresh_choice" in
|
|
1)
|
|
refresh_library "" false
|
|
;;
|
|
2)
|
|
read -p "$(echo -e "${BOLD}Enter section ID:${RESET} ")" section_id
|
|
refresh_library "$section_id" false
|
|
;;
|
|
3)
|
|
refresh_library "" true
|
|
;;
|
|
4)
|
|
read -p "$(echo -e "${BOLD}Enter section ID:${RESET} ")" section_id
|
|
refresh_library "$section_id" true
|
|
;;
|
|
*)
|
|
print_status "${CROSS}" "Invalid choice" "${RED}"
|
|
;;
|
|
esac
|
|
;;
|
|
4)
|
|
echo ""
|
|
echo -e "${BOLD}Analysis Options:${RESET}"
|
|
echo -e "${GREEN}1)${RESET} Analyze all libraries"
|
|
echo -e "${GREEN}2)${RESET} Analyze specific library"
|
|
echo -e "${GREEN}3)${RESET} Deep analyze all libraries"
|
|
echo -e "${GREEN}4)${RESET} Deep analyze specific library"
|
|
read -p "$(echo -e "${BOLD}Choose [1-4]:${RESET} ")" analyze_choice
|
|
|
|
case "$analyze_choice" in
|
|
1)
|
|
analyze_library "" false
|
|
;;
|
|
2)
|
|
read -p "$(echo -e "${BOLD}Enter section ID:${RESET} ")" section_id
|
|
analyze_library "$section_id" false
|
|
;;
|
|
3)
|
|
analyze_library "" true
|
|
;;
|
|
4)
|
|
read -p "$(echo -e "${BOLD}Enter section ID:${RESET} ")" section_id
|
|
analyze_library "$section_id" true
|
|
;;
|
|
*)
|
|
print_status "${CROSS}" "Invalid choice" "${RED}"
|
|
;;
|
|
esac
|
|
;;
|
|
5)
|
|
echo ""
|
|
echo -e "${BOLD}Thumbnail Generation Options:${RESET}"
|
|
echo -e "${GREEN}1)${RESET} Generate for all libraries"
|
|
echo -e "${GREEN}2)${RESET} Generate for specific library"
|
|
read -p "$(echo -e "${BOLD}Choose [1-2]:${RESET} ")" gen_choice
|
|
|
|
case "$gen_choice" in
|
|
1)
|
|
generate_thumbnails ""
|
|
;;
|
|
2)
|
|
read -p "$(echo -e "${BOLD}Enter section ID:${RESET} ")" section_id
|
|
generate_thumbnails "$section_id"
|
|
;;
|
|
*)
|
|
print_status "${CROSS}" "Invalid choice" "${RED}"
|
|
;;
|
|
esac
|
|
;;
|
|
6)
|
|
echo ""
|
|
read -p "$(echo -e "${BOLD}Enter section ID to show tree:${RESET} ")" section_id
|
|
show_library_tree "$section_id"
|
|
;;
|
|
q|Q)
|
|
print_status "${INFO}" "Goodbye!" "${CYAN}"
|
|
break
|
|
;;
|
|
*)
|
|
print_status "${CROSS}" "Invalid choice: $choice" "${RED}"
|
|
;;
|
|
esac
|
|
|
|
echo ""
|
|
echo -e "${DIM}Press Enter to continue...${RESET}"
|
|
read -r
|
|
echo ""
|
|
done
|
|
}
|
|
|
|
# 🚀 Main script logic
|
|
main() {
|
|
# Create log directory if it doesn't exist
|
|
mkdir -p "$LOG_DIR"
|
|
|
|
# Check if running as root
|
|
if [[ $EUID -eq 0 ]]; then
|
|
print_status "${CROSS}" "Don't run this script as root! Use your regular user account." "${RED}"
|
|
exit 1
|
|
fi
|
|
|
|
# Parse command line arguments
|
|
while [[ $# -gt 0 ]]; do
|
|
case $1 in
|
|
-v|--verbose)
|
|
VERBOSE=true
|
|
shift
|
|
;;
|
|
-h|--help)
|
|
show_help
|
|
exit 0
|
|
;;
|
|
*)
|
|
break
|
|
;;
|
|
esac
|
|
done
|
|
|
|
# Check if no arguments provided or interactive requested
|
|
if [[ $# -eq 0 ]] || [[ "${1,,}" == "interactive" ]]; then
|
|
interactive_mode
|
|
exit $?
|
|
fi
|
|
|
|
# Pre-flight checks
|
|
if ! check_plex_service; then
|
|
exit 2
|
|
fi
|
|
|
|
if ! find_scanner; then
|
|
exit 3
|
|
fi
|
|
|
|
# Handle commands
|
|
case "${1,,}" in
|
|
"list")
|
|
list_libraries
|
|
;;
|
|
"scan")
|
|
local section_id="${2:-}"
|
|
scan_library "$section_id"
|
|
;;
|
|
"refresh")
|
|
local section_id="${2:-}"
|
|
local force="${3:-false}"
|
|
refresh_library "$section_id" "$force"
|
|
;;
|
|
"analyze"|"analyse")
|
|
local section_id="${2:-}"
|
|
local deep="${3:-false}"
|
|
analyze_library "$section_id" "$deep"
|
|
;;
|
|
"generate"|"thumbnails")
|
|
local section_id="${2:-}"
|
|
generate_thumbnails "$section_id"
|
|
;;
|
|
"tree")
|
|
local section_id="$2"
|
|
if [[ -z "$section_id" ]]; then
|
|
print_status "${CROSS}" "Section ID required for tree command" "${RED}"
|
|
exit 1
|
|
fi
|
|
show_library_tree "$section_id"
|
|
;;
|
|
"help"|"--help"|"-h")
|
|
show_help
|
|
;;
|
|
*)
|
|
print_status "${CROSS}" "Unknown command: ${RED}${BOLD}$1${RESET}" "${RED}"
|
|
echo ""
|
|
show_help
|
|
exit 1
|
|
;;
|
|
esac
|
|
|
|
# Print footer for successful operations
|
|
print_footer
|
|
}
|
|
|
|
# 🎬 Execute main function with all arguments
|
|
main "$@"
|