#!/bin/bash #运行环境初始化 # shellcheck shell=bash # shellcheck disable=SC2086 # shellcheck disable=SC1091 # shellcheck disable=SC2154 # shellcheck disable=SC2162 PATH=${PATH}:/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:~/bin:/opt/homebrew/bin export PATH Blue="\033[1;34m" Green="\033[1;32m" Red="\033[1;31m" Yellow='\033[1;33m' NC="\033[0m" INFO="[${Green}INFO${NC}]" ERROR="[${Red}ERROR${NC}]" WARN="[${Yellow}WARN${NC}]" function INFO() { echo -e "${INFO} ${1}" } function ERROR() { echo -e "${ERROR} ${1}" } function WARN() { echo -e "${WARN} ${1}" } function root_need() { if [[ $EUID -ne 0 ]]; then ERROR '此脚本必须以 root 身份运行!' exit 1 fi } function ___install_docker() { if ! which docker; then WARN "docker 未安装,脚本尝试自动安装..." wget -qO- get.docker.com | bash if which docker; then INFO "docker 安装成功!" else ERROR "docker 安装失败,请手动安装!" exit 1 fi fi } install_package() { local package=$1 local install_cmd="$2 $package" if ! which $package > /dev/null 2>&1; then WARN "$package 未安装,脚本尝试自动安装..." if eval "$install_cmd"; then INFO "$package 安装成功!" else ERROR "$package 安装失败,请手动安装!" exit 1 fi fi } packages_need() { local update_cmd local install_cmd if [ -f /etc/debian_version ]; then update_cmd="apt update -y" install_cmd="apt install -y" elif [ -f /etc/redhat-release ]; then install_cmd="yum install -y" elif [ -f /etc/SuSE-release ]; then update_cmd="zypper refresh" install_cmd="zypper install" elif [ -f /etc/alpine-release ]; then install_cmd="apk add" elif [ -f /etc/arch-release ]; then update_cmd="pacman -Sy --noconfirm" install_cmd="pacman -S --noconfirm" else ERROR "不支持的操作系统." exit 1 fi [ -n "$update_cmd" ] && eval "$update_cmd" install_package "curl" "$install_cmd" if ! which wget; then install_package "wget" "$install_cmd" fi ___install_docker } #获取小雅alist配置目录路径 function get_config_path(){ docker_name=$(docker ps -a | grep ailg/alist | awk '{print $NF}') if command -v jq;then config_dir=$(docker inspect $docker_name | jq -r '.[].Mounts[] | select(.Destination=="/data") | .Source') else #config_dir=$(docker inspect xiaoya | awk '/"Destination": "\/data"/{print a} {a=$0}'|awk -F\" '{print $4}') config_dir=$(docker inspect --format '{{ (index .Mounts 0).Source }}' "$docker_name") fi echo -e "\033[1;37m找到您的小雅ALIST配置文件路径是: \033[1;35m\n$config_dir\033[0m" echo -e "\n" read -ep "确认请按任意键,或者按N/n手动输入路径(注:上方显示多个路径也请选择手动输入):" f12_select_0 if [[ $f12_select_0 == [Nn] ]]; then echo -e "\033[1;35m请输入您的小雅ALIST配置文件路径:\033[0m" read config_dir if ! [[ -d "$config_dir" && -f "$config_dir/mytoken.txt" ]]; then ERROR "该路径不存在或该路径下没有mytoken.txt配置文件" ERROR "如果你是选择全新目录重装小雅alist,请先删除原来的容器,再重新运行本脚本!" ERROR -e "\033[1;31m您选择的目录不正确,程序退出。\033[0m" exit 1 fi fi } function get_jf_media_path(){ if [[ -z $1 ]];then jf_name=jellyfin_xy else jf_name=$1 fi if command -v jq;then media_dir=$(docker inspect $jf_name | jq -r '.[].Mounts[] | select(.Destination=="/media") | .Source') else media_dir=$(docker inspect $jf_name | awk '/"Destination": "\/media"/{print a} {a=$0}'|awk -F\" '{print $4}') fi if [[ -n $media_dir ]];then media_dir=$(dirname "$media_dir") echo -e "\033[1;37m找到您的小雅姐夫媒体库路径是: \033[1;35m\n$media_dir\033[0m" echo -e "\n" read -ep "确认请按任意键,或者按N/n手动输入路径:" f12_select_2 if [[ $f12_select_2 == [Nn] ]]; then echo -e "\033[1;35m请输入您的小雅姐夫媒体库路径:\033[0m" read media_dir check_path $media_dir fi echo -e "\n" else echo -e "\033[1;35m请输入您的小雅姐夫媒体库路径:\033[0m" read media_dir check_path $media_dir fi } meta_select() { echo -e "———————————————————————————————————— \033[1;33mA I 老 G\033[0m —————————————————————————————————" echo -e "\n" echo -e "\033[1;32m1、config.mp4 —— 小雅姐夫的配置目录数据\033[0m" echo -e "\n" echo -e "\033[1;35m2、all.mp4 —— 除pikpak之外的所有小雅元数据\033[0m" echo -e "\n" echo -e "\033[1;32m3、pikpak.mp4 —— pikpak元数据(需魔法才能观看)\033[0m" echo -e "\n" echo -e "\033[1;32m4、全部安装\033[0m" echo -e "\n" echo -e "——————————————————————————————————————————————————————————————————————————————————" echo -e "请选择您\033[1;31m需要安装\033[0m的元数据(输入序号,多项用逗号分隔):" read f8_select if ! [[ $f8_select =~ ^[1-4]([\,\,][1-4])*$ ]]; then echo "输入的序号无效,请输入1到3之间的数字。" exit 1 fi if ! [[ $f8_select == "4" ]]; then files=("config_jf.mp4" "all_jf.mp4" "pikpak_jf.mp4") for i in {1..3} do file=${files[$i-1]} if ! [[ $f8_select == *$i* ]];then sed -i "/aria2c.*$file/d" /tmp/update_meta_jf.sh sed -i "/7z.*$file/d" /tmp/update_meta_jf.sh else if [[ -f $media_dir/temp/$file ]] && ! [[ -f $media_dir/temp/$file.aria2 ]];then WARN "${Yellow}${file}文件已在${media_dir}/temp目录存在,是否要重新解压?$NC" read -ep "请选择:(是-按任意键,否-按N/n键)" yn if [[ $yn == [Nn] ]];then sed -i "/7z.*$file/d" /tmp/update_meta_jf.sh sed -i "/aria2c.*$file/d" /tmp/update_meta_jf.sh else remote_size=$(curl -sL -D - -o /dev/null --max-time 5 "$docker_addr/d/ailg_jf/${file}" | grep "Content-Length" | cut -d' ' -f2) local_size=$(du -b $media_dir/temp/$file | cut -f1) [[ $remote_size == "$local_size" ]] && sed -i "/aria2c.*$file/d" /tmp/update_meta_jf.sh fi fi fi done fi } function user_select1(){ if [[ $st_alist =~ "已安装" ]];then WARN "您的小雅alist姐夫版已安装,是否需要重装?" read -ep "请选择:(确认重装按Y/y,否则按任意键返回!)" re_setup if [[ $re_setup == [Yy] ]];then check_env get_config_path INFO "小雅alist姐夫版配置路径为:$config_dir" INFO "正在停止和删除旧的小雅alist容器" docker stop $docker_name docker rm $docker_name INFO "$docker_name 容器已删除" else main return fi else check_env INFO "正在检查和删除已安装的小雅alist" rm_alist INFO "原有小雅alist容器已删除" if [[ -n "$config_dir" ]]; then INFO "你原来小雅alist的配置路径是:${Blue}${config_dir}${NC},可使用原有配置继续安装!" read -ep "确认请按任意键,或者按N/n手动输入路径:" user_select_0 if [[ $user_select_0 == [Nn] ]]; then echo -e "\033[1;35m请输入您的小雅ALIST配置文件路径:\033[0m" read config_dir check_path $config_dir INFO "小雅alist姐夫版配置路径为:$config_dir" fi else read -ep "请输入小雅alist的安装路径,使用默认的/etc/xiaoya可直接回车:" config_dir [[ -z $config_dir ]] && config_dir="/etc/xiaoya" check_path $config_dir INFO "小雅alist姐夫版配置路径为:$config_dir" fi fi curl -o /tmp/update_new_jf.sh https://xy.ggbond.org/xy/update_new_jf.sh grep -q "长度不对" /tmp/update_new_jf.sh || { echo -e "文件获取失败,检查网络或重新运行脚本!"; rm -f /tmp/update_new_jf.sh; exit 1; } bash -c "$(cat /tmp/update_new_jf.sh)" -s $config_dir host INFO "${Green}哇塞!你的小雅alist姐夫版安装完成了!$NC" } function user_select2(){ if [[ $st_alist =~ "未安装" ]];then ERROR "请先安装小雅alist姐夫版,再执行本安装!" main return fi if [[ $st_jf =~ "已安装" ]];then WARN "您的小雅姐夫已安装,是否需要重装?" read -ep "请选择:(确认重装按Y/y,否则按任意键返回!)" re_setup if [[ $re_setup == [Yy] ]];then check_env jf_name=$(docker ps -a | grep nyanmisaka/jellyfin:240220 | awk '{print $NF}') get_config_path get_jf_media_path $jf_name docker stop $jf_name docker rm $jf_name else main return fi else get_config_path echo -e "\033[1;35m请输入您的小雅姐夫媒体库路径:\033[0m" read media_dir check_path $media_dir fi if [ -s $config_dir/docker_address.txt ]; then docker_addr=$(head -n1 $config_dir/docker_address.txt) else echo "请先配置 /etc/xiaoya/docker_address.txt,以便获取docker 地址" exit fi mkdir -p $media_dir/xiaoya mkdir -p $media_dir/temp curl -o /tmp/update_meta_jf.sh https://xy.ggbond.org/xy/update_meta_jf.sh meta_select chmod 777 /tmp/update_meta_jf.sh docker run -i --security-opt seccomp=unconfined --rm --net=host -v /tmp:/tmp -v $media_dir:/media -v $config_dir:/etc/xiaoya -e LANG=C.UTF-8 ailg/ggbond:latest bash /tmp/update_meta_jf.sh #dir=$(find $media_dir -type d -name "*config*" -print -quit) mv "$media_dir/jf_config" "$media_dir/config" INFO "正在设置媒体库权限,请耐心等候……" chmod -R 777 $media_dir/config chmod -R 777 $media_dir/xiaoya INFO "媒体库权限设置完成!开始安装jellyfin……" host=$(echo $docker_addr|cut -f1,2 -d:) docker run -d --name jellyfin_xy -v /etc/nsswitch.conf:/etc/nsswitch.conf \ -v $media_dir/config:/config \ -v $media_dir/xiaoya:/media \ -v $media_dir/config/cache:/cache \ --user 0:0 \ -p 6909:8096 \ -p 6920:8920 \ -p 1909:1900/udp \ -p 7369:7359/udp \ --privileged --add-host="xiaoya.host:$(echo $host | cut -d'/' -f3)" --restart always nyanmisaka/jellyfin:240220-amd64-legacy INFO "${Blue}小雅姐夫安装完成,正在为您重启小雅alist!$NC" echo "${host}:6909" > $config_dir/emby_server.txt docker restart xiaoya_jf start_time=$(date +%s) TARGET_LOG_LINE_SUCCESS="success load storage: [/©️" while true; do line=$(docker logs "xiaoya_jf" 2>&1| tail -n 10) echo $line if [[ "$line" == *"$TARGET_LOG_LINE_SUCCESS"* ]]; then break fi current_time=$(date +%s) elapsed_time=$((current_time - start_time)) if [ "$elapsed_time" -gt 300 ]; then echo "小雅alist未正常启动超时 5分钟,请检查小雅alist的安装!" break fi sleep 3 done INFO "请登陆${Green} $host:2345 ${NC}访问小雅姐夫,用户名:${Blue} ailg ${NC},密码:${Green} 5678 ${NC}" } function user_select3(){ user_select1 start_time=$(date +%s) TARGET_LOG_LINE_SUCCESS="success load storage: [/©️" while true; do line=$(docker logs "xiaoya_jf" 2>&1| tail -n 10) echo $line if [[ "$line" == *"$TARGET_LOG_LINE_SUCCESS"* ]]; then break fi current_time=$(date +%s) elapsed_time=$((current_time - start_time)) if [ "$elapsed_time" -gt 300 ]; then echo "小雅alist未正常启动超时 5分钟,程序将退出,请检查小雅alist的安装,或重启小雅alist后重新运行脚本!" exit fi sleep 3 done user_select2 } function main(){ clear st_alist=$(setup_status $(docker ps -a | grep ailg/alist | awk '{print $NF}')) st_jf=$(setup_status $(docker ps -a | grep nyanmisaka/jellyfin:240220 | awk '{print $NF}')) echo -e "\e[33m" echo -e "————————————————————————————————————使 用 说 明————————————————————————————————" echo -e "1、本脚本为小雅Jellyfin全家桶的安装脚本,使用于群晖系统环境,不保证其他系统通用;" echo -e "2、本脚本为个人自用,不维护,不更新,不保证适用每个人的环境,请勿用于商业用途;" echo -e "3、作者不对使用本脚本造成的任何后果负责,有任何顾虑,请勿运行,按CTRL+C立即退出;" echo -e "4、如果您喜欢这个脚本,可以请我喝咖啡:https://xy.ggbond.org/xy/3q.jpg\033[0m" echo -e "————————————————————————————————————\033[1;33m安 装 状 态\033[0m————————————————————————————————" echo -e "\e[0m" echo -e "小雅alist姐夫版:${st_alist}; 小雅姐夫(jellyfin):${st_jf}" echo -e "\e[0m" echo -e "———————————————————————————————————— \033[1;33mA I 老 G\033[0m —————————————————————————————————" echo -e "\n" echo -e "\033[1;32m1、安装/重装小雅ALIST姐夫版\033[0m" echo -e "\n" echo -e "\033[1;35m2、安装/重装小雅姐夫(jellyfin)\033[0m" echo -e "\n" echo -e "\033[1;32m3、无脑一键全装/重装\033[0m" echo -e "\n" echo -e "——————————————————————————————————————————————————————————————————————————————————" read -ep "请输入您的选择(1-3或q退出);" user_select case $user_select in 1) clear user_select1;; 2) clear user_select2;; 3) clear user_select3;; [Qq]) exit 0;; *) ERROR "输入错误,按任意键重新输入!" read -n 1 main esac } setup_status() { if docker container inspect "${1}" > /dev/null 2>&1; then echo -e "${Green}已安装${NC}" else echo -e "${Red}未安装${NC}" fi } #检查用户路径输入 check_path() { dir_path=$1 if [[ ! -d "$dir_path" ]]; then read -ep "您输入的目录不存在,按Y/y创建,或按其他键退出!" yn case $yn in [Yy]* ) mkdir -p $dir_path if [[ ! -d $dir_path ]];then echo "您的输入有误,目录创建失败,程序退出!" exit 1 else chmod 777 $dir_path INFO "${dir_path}目录创建成功!" fi ;; * ) exit 0;; esac fi } #安装环境检查 check_env() { if ! which curl; then packages_need if ! which curl; then ERROR "curl 未安装,请手动安装!" exit 1 fi if ! which wget; then ERROR "wget 未安装,请手动安装!" exit 1 fi if ! which docker; then ERROR "docker 未安装,请手动安装!" exit 1 fi fi } #删除原来的小雅容器 rm_alist() { for container in $(docker ps -aq) do image=$(docker inspect --format '{{.Config.Image}}' "$container") if [[ "$image" == "xiaoyaliu/alist:latest" ]] || [[ "$image" == "xiaoyaliu/alist:hostmode" ]] || [[ "$image" == "ailg/alist:hostmode" ]]; then WARN "本安装会删除原有的小雅alist容器,按任意键继续,或按CTRL+C退出!" read -n 1 echo "Deleting container $container using image $image ..." config_dir=$(docker inspect --format '{{ (index .Mounts 0).Source }}' "$container") docker stop "$container" docker rm "$container" echo "Container $container has been deleted." fi done } main