Last active
July 15, 2024 07:05
-
-
Save ChenyangGao/e8e520de651e6375dad552b5a761902f to your computer and use it in GitHub Desktop.
在服务器部署alist和clouddrive(原来只支持openwrt,现在已通用)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env bash | |
# current_shell_rcfile() { | |
# if [ -n "$BASH_VERSION" ]; then | |
# printf "%s\n" ~/.bashrc | |
# elif [ -n "$ZSH_VERSION" ]; then | |
# printf "%s\n" ~/.zshrc | |
# elif [ -n "$FISH_VERSION" ]; then | |
# printf "%s\n" ~/.config/fish/config.fish | |
# elif [ -n "$XONSH_VERSION" ]; then | |
# printf "%s\n" ~/.xonshrc | |
# else | |
# echo '目前只支持 bash、zsh、fish 和 xonsh' >&2 | |
# exit 1 | |
# fi | |
# } | |
default_shell_rcfile() { | |
case "$(basename $SHELL)" in | |
bash) | |
printf "%s\n" ~/.bashrc | |
;; | |
zsh) | |
printf "%s\n" ~/.zshrc | |
;; | |
fish) | |
printf "%s\n" ~/.config/fish/config.fish | |
;; | |
xonsh) | |
printf "%s\n" ~/.xonshrc | |
;; | |
*) | |
echo '目前只支持 bash、zsh、fish 和 xonsh,你的默认 shell 是:'"$SHELL" >&2 | |
exit 1 | |
;; | |
esac | |
} | |
if command -v alist >&-; then | |
cmd=(alist server --debug) | |
elif [ -f ~/alist.d/alist ]; then | |
cmd=(~/alist.d/alist server --debug) | |
else | |
echo '未能找到 alist 可执行文件: | |
1. 在 $PATH 中未找到 alist | |
2. 没有可执行文件 ~/alist.d/alist | |
' >&2 | |
exit 1 | |
fi | |
file=$0 | |
if ! [ -x "$file" ]; then | |
chmod +x "$file" | |
fi | |
#:------------------------------:# | |
run() { | |
while true; do | |
"${cmd[@]}" | |
if [ $? -eq 0 ]; then | |
break | |
fi | |
done | |
} | |
start() { | |
if [ $# -eq 0 ]; then | |
pgrep -f "${cmd[*]}" >&- || run | |
else | |
start & | |
fi | |
} | |
stop() { | |
pgrep -f "${cmd[*]}" | xargs -r kill | |
} | |
restart() { | |
stop | |
start "$@" | |
} | |
status() { | |
local pids=($(pgrep -f "${cmd[*]}")) | |
if [ ${#pids[@]} -gt 0 ]; then | |
local args=() | |
for pid in "${pids[@]}"; do | |
args+=("-p" $pid) | |
done | |
top "${args[@]}" | |
fi | |
} | |
log() { | |
tail -f ~/alist.log | |
} | |
enable() { | |
local rcfile=$1 | |
if [ -z "$rcfile" ]; then | |
rcfile=$(default_shell_rcfile) | |
fi | |
grep -q '# startup:alist\.sh$' "$rcfile" || echo "'$file' start -d &>>~/alist.log # startup:alist.sh" >> "$rcfile" | |
} | |
disable() { | |
local rcfile=$1 | |
if [ -z "$rcfile" ]; then | |
rcfile=$(default_shell_rcfile) | |
fi | |
sed -i "/# startup:alist\.sh\$/d" "$rcfile" | |
} | |
#:------------------------------:# | |
cd ~ | |
case "$1" in | |
start | stop | restart | status | log | enable | disable) | |
"$1" "${@:2}" | |
;; | |
startup) | |
enable "${@:2}" | |
;; | |
unstartup) | |
disable "${@:2}" | |
;; | |
*) | |
echo '>>> 帮助信息 | |
start 启动 alist。可指定 -d 后台运行。 | |
———————————————————— | |
stop 停止 alist。 | |
———————————————————— | |
restart 重启 alist。可指定 -d 后台运行。 | |
———————————————————— | |
status 显示 alist 的进程信息。 | |
———————————————————— | |
log 显示 alist 的日志信息。 | |
———————————————————— | |
enable 打开终端后自动启动 alist,可指定一个 rcfile 的路径作为参数,否则自动根据默认 shell 来确定。 | |
通过在默认 SHELL 的 rcfile 文件中写入启动命令来实现,日志在 ~/alist.log。 | |
———————————————————— | |
disable 去除 enable 注册的启动,可指定一个 rcfile 的路径作为参数,否则自动根据默认 shell 来确定。 | |
———————————————————— | |
startup 等同于 enable。 | |
———————————————————— | |
unstartup 等同于 disable。 | |
' | |
;; | |
esac |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env bash | |
# current_shell_rcfile() { | |
# if [ -n "$BASH_VERSION" ]; then | |
# printf "%s\n" ~/.bashrc | |
# elif [ -n "$ZSH_VERSION" ]; then | |
# printf "%s\n" ~/.zshrc | |
# elif [ -n "$FISH_VERSION" ]; then | |
# printf "%s\n" ~/.config/fish/config.fish | |
# elif [ -n "$XONSH_VERSION" ]; then | |
# printf "%s\n" ~/.xonshrc | |
# else | |
# echo '目前只支持 bash、zsh、fish 和 xonsh' >&2 | |
# exit 1 | |
# fi | |
# } | |
default_shell_rcfile() { | |
case "$(basename $SHELL)" in | |
bash) | |
printf "%s\n" ~/.bashrc | |
;; | |
zsh) | |
printf "%s\n" ~/.zshrc | |
;; | |
fish) | |
printf "%s\n" ~/.config/fish/config.fish | |
;; | |
xonsh) | |
printf "%s\n" ~/.xonshrc | |
;; | |
*) | |
echo '目前只支持 bash、zsh、fish 和 xonsh,你的默认 shell 是:'"$SHELL" >&2 | |
exit 1 | |
;; | |
esac | |
} | |
if command -v clouddrive >&-; then | |
cmd=(clouddrive) | |
elif [ -f ~/clouddrive.d/clouddrive ]; then | |
cmd=(~/clouddrive.d/clouddrive) | |
else | |
echo '未能找到 clouddrive 可执行文件: | |
1. 在 $PATH 中未找到 clouddrive | |
2. 没有可执行文件 ~/clouddrive.d/clouddrive | |
' >&2 | |
exit 1 | |
fi | |
file=$0 | |
if ! [ -x "$file" ]; then | |
chmod +x "$file" | |
fi | |
#:------------------------------:# | |
run() { | |
while true; do | |
"${cmd[@]}" | |
if [ $? -eq 0 ]; then | |
break | |
fi | |
done | |
} | |
start() { | |
if [ $# -eq 0 ]; then | |
pgrep -f "${cmd[*]}" >&- || run | |
else | |
start & | |
fi | |
} | |
stop() { | |
pgrep -f "${cmd[*]}" | xargs -r kill | |
} | |
restart() { | |
stop | |
start "$@" | |
} | |
status() { | |
local pids=($(pgrep -f "${cmd[*]}")) | |
if [ ${#pids[@]} -gt 0 ]; then | |
local args=() | |
for pid in "${pids[@]}"; do | |
args+=("-p" $pid) | |
done | |
top "${args[@]}" | |
fi | |
} | |
log() { | |
tail -f ~/clouddrive.log | |
} | |
enable() { | |
local rcfile=$1 | |
if [ -z "$rcfile" ]; then | |
rcfile=$(default_shell_rcfile) | |
fi | |
grep -q '# startup:clouddrive\.sh$' "$rcfile" || echo "'$file' start -d &>>~/clouddrive.log # startup:clouddrive.sh" >> "$rcfile" | |
} | |
disable() { | |
local rcfile=$1 | |
if [ -z "$rcfile" ]; then | |
rcfile=$(default_shell_rcfile) | |
fi | |
sed -i "/# startup:clouddrive\.sh\$/d" "$rcfile" | |
} | |
#:------------------------------:# | |
cd ~ | |
case "$1" in | |
start | stop | restart | status | log | enable | disable) | |
"$1" "${@:2}" | |
;; | |
startup) | |
enable "${@:2}" | |
;; | |
unstartup) | |
disable "${@:2}" | |
;; | |
*) | |
echo '>>> 帮助信息 | |
start 启动 clouddrive。可指定 -d 后台运行。 | |
———————————————————— | |
stop 停止 clouddrive。 | |
———————————————————— | |
restart 重启 clouddrive。可指定 -d 后台运行。 | |
———————————————————— | |
status 显示 clouddrive 的进程信息。 | |
———————————————————— | |
log 显示 clouddrive 的日志信息。 | |
———————————————————— | |
enable 打开终端后自动启动 clouddrive,可指定一个 rcfile 的路径作为参数,否则自动根据默认 shell 来确定。 | |
通过在默认 SHELL 的 rcfile 文件中写入启动命令来实现,日志在 ~/clouddrive.log。 | |
———————————————————— | |
disable 去除 enable 注册的启动,可指定一个 rcfile 的路径作为参数,否则自动根据默认 shell 来确定。 | |
———————————————————— | |
startup 等同于 enable。 | |
———————————————————— | |
unstartup 等同于 disable。 | |
' | |
;; | |
esac |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env bash | |
# NOTE 这个脚本可以用 bash 或 zsh 运行,在 Linux 下请用 root 权限运行,否则不会尝试设置开机自启动服务 | |
# NOTE 可用环境变量 VERSION 指定要下载的版本号 | |
# NOTE 可用环境变量 NOSTARTUP 禁用自动设置开机启动 | |
# NOTE 操作系统中必须安装有 wget (我不用 curl,因为 curl 访问 github 好像有 bug,经常返回空页面) | |
if ! command -v wget >&-; then | |
echo '请安装 wget' >&2 | |
exit 1 | |
fi | |
# inetutils (apt) | |
# net-tools (yum) | |
get-local-ipv4-using-hostname() { | |
hostname -I 2>&- | awk '{print $1}' | |
} | |
# iproute2 | |
get-local-ipv4-using-iproute2() { | |
# OR ip route get 1.2.3.4 | awk '{print $7}' | |
ip -4 route 2>&- | awk '{print $NF}' | grep -Eo --color=never '[0-9]+(\.[0-9]+){3}' | |
} | |
# net-tools | |
get-local-ipv4-using-ifconfig() { | |
( ifconfig 2>&- || ip addr show 2>&- ) | grep -Eo '^\s+inet\s+\S+' | grep -Eo '[0-9]+(\.[0-9]+){3}' | grep -Ev '127\.0\.0\.1|0\.0\.0\.0' | |
} | |
# 获取本机 IPv4 地址 | |
get-local-ipv4() { | |
set -o pipefail | |
get-local-ipv4-using-hostname || get-local-ipv4-using-iproute2 || get-local-ipv4-using-ifconfig | |
} | |
# 获取本机 IPv4 地址(只取第一个) | |
get-local-ipv4-select() { | |
local ips=$(get-local-ipv4) | |
local retcode=$? | |
if [ $retcode -ne 0 ]; then | |
return $retcode | |
fi | |
grep -m 1 "^192\." <<<"$ips" || \ | |
grep -m 1 "^172\." <<<"$ips" || \ | |
grep -m 1 "^10\." <<<"$ips" || \ | |
head -n 1 <<<"$ips" | |
} | |
# 操作系统的名称 | |
PLATFORM=$(uname -s) | |
# 操作系统的 CPU 架构 | |
ARCH=$(uname -m) | |
# alist 项目的 github 主页链接 | |
ALIST_GITHUB_URL=https://github.com/alist-org/alist | |
# 默认的 alist 软件包,会根据系统信息自动确定,不能确定的留空 | |
ALIST_DEFAULT_ASSET= | |
# 已选择的 alist 软件包,此参数被 download-asset 函数设置 | |
ALIST_SELECTED_ASSET= | |
if [ "$PLATFORM" = 'Darwin' ]; then | |
if [ "$ARCH" = 'arm64' ] || [ "$ARCH" = 'aarch64' ]; then | |
ALIST_DEFAULT_ASSET=alist-darwin-arm64.tar.gz | |
elif [ "$ARCH" = 'x86_64' ] || [ "$ARCH" = 'amd64' ]; then | |
ALIST_DEFAULT_ASSET=alist-darwin-amd64.tar.gz | |
fi | |
elif [ "$PLATFORM" = 'Linux' ]; then | |
if [ "$ARCH" = 'arm64' ] || [ "$ARCH" = 'aarch64' ]; then | |
ALIST_DEFAULT_ASSET=alist-linux-musl-arm64.tar.gz | |
elif [ "$arch" = 'armv7l' ]; then | |
ALIST_DEFAULT_ASSET=alist-linux-musleabihf-armv7l.tar.gz | |
elif [ "$ARCH" = 'x86_64' ] || [ "$ARCH" = 'amd64' ]; then | |
ALIST_DEFAULT_ASSET=alist-linux-musl-amd64.tar.gz | |
elif [ "$ARCH" = 'mips' ]; then | |
ALIST_DEFAULT_ASSET=alist-linux-musl-mips.tar.gz | |
elif [ "$ARCH" = 'mipsle' ]; then | |
ALIST_DEFAULT_ASSET=alist-linux-musl-mipsle.tar.gz | |
elif [ "$ARCH" = 'mips64' ]; then | |
ALIST_DEFAULT_ASSET=alist-linux-musl-mips64.tar.gz | |
elif [ "$ARCH" = 'mips64le' ]; then | |
ALIST_DEFAULT_ASSET=alist-linux-musl-mipsle.tar.gz | |
elif [ "$ARCH" = 'ppc64le' ]; then | |
ALIST_DEFAULT_ASSET=alist-linux-musl-ppc64le.tar.gz | |
elif [ "$ARCH" = 'riscv64' ]; then | |
ALIST_DEFAULT_ASSET=alist-linux-riscv64.tar.gz | |
elif [ "$ARCH" = 's390x' ]; then | |
ALIST_DEFAULT_ASSET=alist-linux-musl-s390x.tar.gz | |
fi | |
# NOTE 暂时不管 Windows | |
# elif [ "$PLATFORM" = 'Windows' ]; then | |
fi | |
# 当前系统所用的进程启动器 | |
SYSTEM_INIT= | |
if [ -n "${NOSTARTUP+x}" ]; then | |
SYSTEM_INIT=unset | |
elif [ "$PLATFORM" = 'Darwin' ]; then | |
SYSTEM_INIT=$(ps -p 1 -o comm=) | |
elif [ "$PLATFORM" = 'Linux' ]; then | |
# ps -p 1 -o comm= # NOTE 也可以用这个命令,但是但有些嵌入式系统,ps 没有 -p 选项 | |
# SYSTEM_INIT=$(cat /proc/1/cmdline) | |
SYSTEM_INIT=$(cat /proc/1/comm) | |
# NOTE 暂时不管 Windows | |
# elif [ "$PLATFORM" = 'Windows' ]; then | |
# # services.exe 和 lsass.exe 进程通常是由 Windows 的启动器(服务控制管理器)启动的 | |
# # tasklist | findstr /i "services.exe lsass.exe" | |
fi | |
# 获取某个 github 页面的响应。$1: github 链接。 | |
request-github-url() { | |
local url=$1 | |
if [ -z "$url" ]; then | |
echo '不能是空链接' >&2 | |
return 1 | |
elif [[ $url == /* ]]; then | |
url=https://github.com$url | |
elif [ "$url" = https://github.com ]; then | |
true | |
elif [[ $url != https://github.com/* ]]; then | |
url=https://github.com/$url | |
fi | |
local page=$(wget -q -O - "$url") | |
local retcode=$? | |
# NOTE 我发现,如果使用 curl,可能会因为访问失败,而返回空页面,虽然目前使用 wget,但为了以防万一 | |
while [ -z "$page" ]; do | |
echo $'\x1b[38;5;1m\x1b[1mRETRYING\x1b[0m:' "$url" >&2 | |
page=$(wget -q -O - "$url") | |
retcode=$? | |
done | |
if [ $retcode -ne 0 ]; then | |
echo -n "$page" >&2 | |
return $retcode | |
fi | |
echo -n "$page" | |
} | |
# 下载软件包,如果软件包已存在,则跳过。$1: 版本号。 | |
download-asset() { | |
local version=$1 | |
local release_link= | |
if [ -z "$version" ] || ! [[ "$version" =~ ^v?[0-9.]+$ ]] ; then | |
release_link=$ALIST_GITHUB_URL/releases/latest | |
release_link=$(wget -q --server-response --max-redirect=0 - $release_link 2>&1 | grep -i location | grep -o 'http.*') | |
version=$(basename "$release_link") | |
else | |
if [[ "$version" != v* ]]; then | |
version=v$version | |
fi | |
release_link=$ALIST_GITHUB_URL/releases/tag/$version | |
fi | |
local assets_link="${release_link/\/tag\///expanded_assets/}" | |
local assets_page=$(request-github-url "$assets_link") | |
local ifs=$IFS | |
local var | |
IFS=$'\n' | |
local links=() | |
for var in $(echo "$assets_page" | grep -o 'href="[^"]\+'); do | |
links+=("${var/href=\"/https://github.com}") | |
done | |
IFS=$ifs | |
local length=${#links[@]} | |
local flag=0 | |
IFS=$'\n' | |
local names=() | |
for var in $(echo "$assets_page" | grep '^ <span' | grep -o '>[^<]*<'); do | |
if [ $flag -eq 0 ]; then | |
names+=("${var:1:-1}") | |
flag=1 | |
else | |
names[-1]="${names[-1]}""${var:1:-1}" | |
flag=0 | |
fi | |
done | |
IFS=$ifs | |
local default_index | |
if [ -n "$ZSH_VERSION" ]; then | |
for ((i=1; i<=$length; i++)); do | |
if [ "${names[$i]}" = "$ALIST_DEFAULT_ASSET" ]; then | |
default_index=$i | |
fi | |
printf '%2s | ' $i | |
echo "${names[$i]} |" "${links[$i]}" | |
done | |
else | |
for ((i=0; i<$length; i++)); do | |
if [ "${names[$i]}" = "$ALIST_DEFAULT_ASSET" ]; then | |
default_index=$i | |
fi | |
printf '%2s | ' $i | |
echo "${names[$i]} |" "${links[$i]}" | |
done | |
fi | |
local link name chosen_index | |
if [ -z "$default_index" ]; then | |
while true; do | |
echo -n "请选择一个数字:" | |
read chosen_index | |
chosen_index=$(tr -d '[:space:]' <<<"$chosen_index") | |
if [ -z "$chosen_index" ]; then | |
continue | |
fi | |
link="${links[$chosen_index]}" | |
if [ -z "$link" ]; then | |
continue | |
fi | |
name="${names[$chosen_index]}" | |
break | |
done | |
else | |
while true; do | |
echo -n "请选择一个数字(默认值 $default_index):" | |
read chosen_index | |
chosen_index=$(tr -d '[:space:]' <<<"$chosen_index") | |
if [ -z "$chosen_index" ]; then | |
chosen_index=default_index | |
fi | |
link="${links[$chosen_index]}" | |
if [ -z "$link" ]; then | |
continue | |
fi | |
name="${names[$chosen_index]}" | |
break | |
done | |
fi | |
ALIST_SELECTED_ASSET=${version}_$name | |
if ! [ -f "$ALIST_SELECTED_ASSET" ]; then | |
wget -O "$ALIST_SELECTED_ASSET" "$link" | |
fi | |
} | |
################################################################ | |
cd ~ | |
download-asset "$VERSION" | |
if [ $? -ne 0 ]; then | |
echo '获取软件包失败' >&2 | |
exit 1 | |
fi | |
mkdir -p ~/alist.d/data | |
tar --overwrite -xzf "$ALIST_SELECTED_ASSET" -C alist.d | |
# NOTE 因为在我的 openwrt 上 pgrep 没有 -u 选项 😂 | |
if pgrep -u a $USER &>/dev/null; then | |
pgrep_arr=(pgrep -u $USER) | |
else | |
pgrep_arr=(pgrep) | |
fi | |
echo | |
if [ $EUID -eq 0 ]; then | |
prep=() | |
else | |
prep=(sudo) | |
fi | |
case $(basename "$SYSTEM_INIT") in | |
'launchd') | |
if [ $EUID -eq 0 ]; then | |
service=alist | |
else | |
service=alist-$USER | |
fi | |
service_file="$HOME/Library/LaunchAgents/$service.plist" | |
mkdir -p "$HOME/Library/LaunchAgents" | |
echo $'\x1b[38;5;2m\x1b[1mService file\x1b[0m:' "$service_file" | |
echo $'\x1b[38;5;2m\x1b[1m>>>\x1b[0m' | |
tee "$service_file" << EOF | |
<?xml version="1.0" encoding="UTF-8"?> | |
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> | |
<plist version="1.0"> | |
<dict> | |
<key>Description</key> | |
<string>ALIST - 🗂️ A file list program that supports multiple storage, powered by Gin and Solidjs.</string> | |
<key>Documentation</key> | |
<string>https://alist.nn.ci/guide/</string> | |
<key>Label</key> | |
<string>com.alist</string> | |
<key>UserName</key> | |
<string>$USER</string> | |
<key>KeepAlive</key> | |
<true /> | |
<key>ProgramArguments</key> | |
<array> | |
<string>/bin/sh</string> | |
<string>-c</string> | |
<string>'$HOME/alist.d/alist' server --data '$HOME/alist.d/data'</string> | |
</array> | |
<key>RunAtLoad</key> | |
<true /> | |
<key>OnDemand</key> | |
<false /> | |
<key>LaunchOnlyOnce</key> | |
<true /> | |
<key>StandardErrorPath</key> | |
<string>/tmp/$service.err</string> | |
<key>StandardOutPath</key> | |
<string>/tmp/$service.out</string> | |
</dict> | |
</plist> | |
EOF | |
if [ $? -eq 0 ]; then | |
echo $'\x1b[38;5;2m\x1b[1m<<<\x1b[0m' | |
echo $'\x1b[38;5;2m\x1b[1mSTART service\x1b[0m:' "launchctl load -w '$service_file'" | |
echo $'\x1b[38;5;2m\x1b[1mSTOP service\x1b[0m:' "launchctl unload '$service_file'" | |
launchctl unload "$service_file" 2>&- | |
launchctl load -w "$service_file" | |
fi | |
;; | |
'systemd') | |
if [ $EUID -eq 0 ]; then | |
service=alist | |
else | |
service=alist-$USER | |
fi | |
service_file=/etc/systemd/system/$service.service | |
echo $'\x1b[38;5;2m\x1b[1mService file\x1b[0m:' "$service_file" | |
echo $'\x1b[38;5;2m\x1b[1m>>>\x1b[0m' | |
"${prep[@]}" tee "$service_file" << EOF | |
[Unit] | |
Description='ALIST - 🗂️ A file list program that supports multiple storage, powered by Gin and Solidjs.' | |
Documentation='https://alist.nn.ci/guide/' | |
After=network.target | |
[Service] | |
Type=simple | |
User=$USER | |
Restart=on-failure | |
ExecStart='$HOME/alist.d/alist' server --data '$HOME/alist.d/data' | |
[Install] | |
WantedBy=default.target | |
EOF | |
if [ $? -eq 0 ]; then | |
echo $'\x1b[38;5;2m\x1b[1m<<<\x1b[0m' | |
echo $'\x1b[38;5;2m\x1b[1mSTART service\x1b[0m:' "service $service start" | |
echo $'\x1b[38;5;2m\x1b[1mSTOP service\x1b[0m:' "systemctl start $service" | |
echo $'\x1b[38;5;2m\x1b[1mSTART service\x1b[0m:' "service $service stop" | |
echo $'\x1b[38;5;2m\x1b[1mSTOP service\x1b[0m:' "systemctl stop $service" | |
"${prep[@]}" systemctl enable "$service" | |
"${prep[@]}" systemctl stop "$service" | |
"${prep[@]}" systemctl start "$service" | |
fi | |
;; | |
'init') | |
if [ $EUID -eq 0 ]; then | |
service=alist | |
else | |
service=alist-$USER | |
fi | |
service_file=/etc/init/$service.conf | |
echo $'\x1b[38;5;2m\x1b[1mService file\x1b[0m:' "$service_file" | |
echo $'\x1b[38;5;2m\x1b[1m>>>\x1b[0m' | |
"${prep[@]}" tee "$service_file" << EOF | |
description "ALIST - 🗂️ A file list program that supports multiple storage, powered by Gin and Solidjs." | |
documentation "https://alist.nn.ci/guide/" | |
start on filesystem or runlevel [2345] | |
stop on runlevel [!2345] | |
respawn | |
exec '$HOME/alist.d/alist' server --data '$HOME/alist.d/data' | |
EOF | |
if [ $? -eq 0 ]; then | |
echo $'\x1b[38;5;2m\x1b[1m<<<\x1b[0m' | |
echo $'\x1b[38;5;2m\x1b[1mSTART service\x1b[0m:' "service $service start" | |
echo $'\x1b[38;5;2m\x1b[1mSTOP service\x1b[0m:' "service $service stop" | |
"${prep[@]}" service "$service" enable | |
"${prep[@]}" service "$service" stop | |
"${prep[@]}" service "$service" start | |
fi | |
;; | |
'procd') | |
if [ $EUID -eq 0 ]; then | |
service=alist | |
else | |
service=alist-$USER | |
fi | |
service_file=/etc/init.d/$service | |
echo $'\x1b[38;5;2m\x1b[1mService file\x1b[0m:' "$service_file" | |
echo $'\x1b[38;5;2m\x1b[1m>>>\x1b[0m' | |
"${prep[@]}" tee "$service_file" << EOF | |
#!/bin/sh /etc/rc.common | |
USE_PROCD=1 | |
START=99 | |
STOP=99 | |
Description='ALIST - 🗂️ A file list program that supports multiple storage, powered by Gin and Solidjs.' | |
Documentation='https://alist.nn.ci/guide/' | |
start_service() { | |
procd_open_instance | |
procd_set_param command '$HOME/alist.d/alist' server --data '$HOME/alist.d/data' | |
procd_set_param respawn | |
procd_set_param user $USER | |
procd_set_param stdout 1 | |
procd_set_param stderr 1 | |
procd_set_param pidfile /var/run/alist-$USER.pid | |
procd_close_instance | |
} | |
EOF | |
if [ $? -eq 0 ]; then | |
echo $'\x1b[38;5;2m\x1b[1m<<<\x1b[0m' | |
"${prep[@]}" chmod +x "$service_file" | |
echo $'\x1b[38;5;2m\x1b[1mSTART service\x1b[0m:' "service $service start" | |
echo $'\x1b[38;5;2m\x1b[1mSTOP service\x1b[0m:' "service $service stop" | |
"${prep[@]}" service "$service" enable | |
"${prep[@]}" service "$service" stop | |
"${prep[@]}" service "$service" start | |
fi | |
;; | |
*) # 默认情况 | |
echo $'\x1b[38;5;2m\x1b[1mSTART service\x1b[0m:' "'$HOME/alist.d/alist' start --data '$HOME/alist.d/data'" | |
echo $'\x1b[38;5;2m\x1b[1mSTOP service\x1b[0m:' "'$HOME/alist.d/alist' stop" | |
# NOTE 如果有已经运行的实例,终结之 | |
"${pgrep_arr[@]}" alist | xargs kill -9 | |
"$HOME/alist.d/alist" start --data "$HOME/alist.d/data" | |
;; | |
esac | |
~/alist.d/alist admin --data ~/alist.d/data | |
echo | |
echo -e '\x1b[38;5;3mDocumentation\x1b[0m: https://alist.nn.ci/guide/' | |
echo -e "\x1b[38;5;3mServer on\x1b[0m: http://$(get-local-ipv4-select):5244" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env bash | |
# NOTE 这个脚本可以用 bash 或 zsh 运行,在 Linux 下请用 root 权限运行,否则不会尝试设置开机自启动服务 | |
# NOTE 可用环境变量 VERSION 指定要下载的版本号 | |
# NOTE 可用环境变量 NOSTARTUP 禁用自动设置开机启动 | |
# NOTE 操作系统中必须安装有 wget (我不用 curl,因为 curl 访问 github 好像有 bug,经常返回空页面) | |
if ! command -v wget >&-; then | |
echo '请安装 wget' >&2 | |
exit 1 | |
fi | |
# inetutils (apt) | |
# net-tools (yum) | |
get-local-ipv4-using-hostname() { | |
hostname -I 2>&- | awk '{print $1}' | |
} | |
# iproute2 | |
get-local-ipv4-using-iproute2() { | |
# OR ip route get 1.2.3.4 | awk '{print $7}' | |
ip -4 route 2>&- | awk '{print $NF}' | grep -Eo --color=never '[0-9]+(\.[0-9]+){3}' | |
} | |
# net-tools | |
get-local-ipv4-using-ifconfig() { | |
( ifconfig 2>&- || ip addr show 2>&- ) | grep -Eo '^\s+inet\s+\S+' | grep -Eo '[0-9]+(\.[0-9]+){3}' | grep -Ev '127\.0\.0\.1|0\.0\.0\.0' | |
} | |
# 获取本机 IPv4 地址 | |
get-local-ipv4() { | |
set -o pipefail | |
get-local-ipv4-using-hostname || get-local-ipv4-using-iproute2 || get-local-ipv4-using-ifconfig | |
} | |
# 获取本机 IPv4 地址(只取第一个) | |
get-local-ipv4-select() { | |
local ips=$(get-local-ipv4) | |
local retcode=$? | |
if [ $retcode -ne 0 ]; then | |
return $retcode | |
fi | |
grep -m 1 "^192\." <<<"$ips" || \ | |
grep -m 1 "^172\." <<<"$ips" || \ | |
grep -m 1 "^10\." <<<"$ips" || \ | |
head -n 1 <<<"$ips" | |
} | |
# 操作系统的名称 | |
PLATFORM=$(uname -s) | |
# 操作系统的 CPU 架构 | |
ARCH=$(uname -m) | |
# clouddrive 项目的 github 主页链接 | |
CLOUDDRIVE_GITHUB_URL=https://github.com/cloud-fs/cloud-fs.github.io | |
# 默认的 clouddrive 软件包,会根据系统信息自动确定,不能确定的留空 | |
CLOUDDRIVE_DEFAULT_ASSET_PREFIX= | |
# 已选择的 clouddrive 软件包,此参数被 download-asset 函数设置 | |
CLOUDDRIVE_SELECTED_ASSET= | |
if [ "$PLATFORM" = 'Darwin' ]; then | |
if [ "$ARCH" = 'arm64' ] || [ "$ARCH" = 'aarch64' ]; then | |
CLOUDDRIVE_DEFAULT_ASSET_PREFIX=clouddrive-2-macos-aarch64 | |
elif [ "$ARCH" = 'x86_64' ] || [ "$ARCH" = 'amd64' ]; then | |
CLOUDDRIVE_DEFAULT_ASSET_PREFIX=clouddrive-2-macos-x86_64 | |
fi | |
elif [ "$PLATFORM" = 'Linux' ]; then | |
if [ "$(uname -o)" = 'Android' ]; then | |
os=android | |
else | |
os=linux | |
fi | |
if [ "$ARCH" = 'arm64' ] || [ "$ARCH" = 'aarch64' ]; then | |
CLOUDDRIVE_DEFAULT_ASSET_PREFIX=clouddrive-2-$os-aarch64 | |
elif [ "$arch" = 'armv7l' ] || [ "$arch" = 'armv7' ]; then | |
CLOUDDRIVE_DEFAULT_ASSET_PREFIX=clouddrive-2-$os-armv7 | |
elif [ "$ARCH" = 'x86_64' ] || [ "$ARCH" = 'amd64' ]; then | |
CLOUDDRIVE_DEFAULT_ASSET_PREFIX=clouddrive-2-$os-x86_64 | |
else | |
CLOUDDRIVE_DEFAULT_ASSET_PREFIX=clouddrive-2-$os-$ARCH | |
fi | |
# NOTE 暂时不管 Windows | |
# elif [ "$PLATFORM" = 'Windows' ]; then | |
fi | |
# 当前系统所用的进程启动器 | |
SYSTEM_INIT= | |
if [ -n "${NOSTARTUP+x}" ]; then | |
SYSTEM_INIT=unset | |
elif [ "$PLATFORM" = 'Darwin' ]; then | |
SYSTEM_INIT=$(ps -p 1 -o comm=) | |
elif [ "$PLATFORM" = 'Linux' ]; then | |
# ps -p 1 -o comm= # NOTE 也可以用这个命令,但是但有些嵌入式系统,ps 没有 -p 选项 | |
# SYSTEM_INIT=$(cat /proc/1/cmdline) | |
SYSTEM_INIT=$(cat /proc/1/comm) | |
# NOTE 暂时不管 Windows | |
# elif [ "$PLATFORM" = 'Windows' ]; then | |
# # services.exe 和 lsass.exe 进程通常是由 Windows 的启动器(服务控制管理器)启动的 | |
# # tasklist | findstr /i "services.exe lsass.exe" | |
fi | |
# 获取某个 github 页面的响应。$1: github 链接。 | |
request-github-url() { | |
local url=$1 | |
if [ -z "$url" ]; then | |
echo '不能是空链接' >&2 | |
return 1 | |
elif [[ $url == /* ]]; then | |
url=https://github.com$url | |
elif [ "$url" = https://github.com ]; then | |
true | |
elif [[ $url != https://github.com/* ]]; then | |
url=https://github.com/$url | |
fi | |
local page=$(wget -q -O - "$url") | |
local retcode=$? | |
# NOTE 我发现,如果使用 curl,可能会因为访问失败,而返回空页面,虽然目前使用 wget,但为了以防万一 | |
while [ -z "$page" ]; do | |
echo $'\x1b[38;5;1m\x1b[1mRETRYING\x1b[0m:' "$url" >&2 | |
page=$(wget -q -O - "$url") | |
retcode=$? | |
done | |
if [ $retcode -ne 0 ]; then | |
echo -n "$page" >&2 | |
return $retcode | |
fi | |
echo -n "$page" | |
} | |
# 下载软件包,如果软件包已存在,则跳过。$1: 版本号。 | |
download-asset() { | |
local version=$1 | |
local release_link= | |
if [ -z "$version" ] || ! [[ "$version" =~ ^v?[0-9.]+$ ]] ; then | |
release_link=$CLOUDDRIVE_GITHUB_URL/releases/latest | |
release_link=$(wget -q --server-response --max-redirect=0 - $release_link 2>&1 | grep -i location | grep -o 'http.*') | |
version=$(basename "$release_link") | |
else | |
if ! [[ "$version" == v* ]]; then | |
version=v$version | |
fi | |
release_link=$CLOUDDRIVE_GITHUB_URL/releases/tag/$version | |
fi | |
local assets_link="${release_link/\/tag\///expanded_assets/}" | |
local assets_page=$(request-github-url "$assets_link") | |
local ifs=$IFS | |
local var | |
IFS=$'\n' | |
local links=() | |
for var in $(echo "$assets_page" | grep -o 'href="[^"]\+'); do | |
links+=("${var/href=\"/https://github.com}") | |
done | |
IFS=$ifs | |
local length=${#links[@]} | |
local flag=0 | |
IFS=$'\n' | |
local names=() | |
for var in $(echo "$assets_page" | grep '^ <span' | grep -o '>[^<]*<'); do | |
if [ $flag -eq 0 ]; then | |
names+=("${var:1:-1}") | |
flag=1 | |
else | |
names[-1]="${names[-1]}""${var:1:-1}" | |
flag=0 | |
fi | |
done | |
IFS=$ifs | |
local default_index | |
if [ -n "$ZSH_VERSION" ]; then | |
for ((i=1; i<=$length; i++)); do | |
if [[ "${names[$i]}" == "$CLOUDDRIVE_DEFAULT_ASSET_PREFIX"* ]]; then | |
default_index=$i | |
fi | |
printf '%2s | ' $i | |
echo "${names[$i]} |" "${links[$i]}" | |
done | |
else | |
for ((i=0; i<$length; i++)); do | |
if [[ "${names[$i]}" == "$CLOUDDRIVE_DEFAULT_ASSET_PREFIX"* ]]; then | |
default_index=$i | |
fi | |
printf '%2s | ' $i | |
echo "${names[$i]} |" "${links[$i]}" | |
done | |
fi | |
local link name chosen_index | |
if [ -z "$default_index" ]; then | |
while true; do | |
echo -n "请选择一个数字:" | |
read chosen_index | |
chosen_index=$(tr -d '[:space:]' <<<"$chosen_index") | |
if [ -z "$chosen_index" ]; then | |
continue | |
fi | |
link="${links[$chosen_index]}" | |
if [ -z "$link" ]; then | |
continue | |
fi | |
name="${names[$chosen_index]}" | |
break | |
done | |
else | |
while true; do | |
echo -n "请选择一个数字(默认值 $default_index):" | |
read chosen_index | |
chosen_index=$(tr -d '[:space:]' <<<"$chosen_index") | |
if [ -z "$chosen_index" ]; then | |
chosen_index=default_index | |
fi | |
link="${links[$chosen_index]}" | |
if [ -z "$link" ]; then | |
continue | |
fi | |
name="${names[$chosen_index]}" | |
break | |
done | |
fi | |
CLOUDDRIVE_SELECTED_ASSET=$name | |
if ! [ -f "$CLOUDDRIVE_SELECTED_ASSET" ]; then | |
wget "$link" | |
fi | |
} | |
################################################################ | |
cd ~ | |
download-asset "$VERSION" | |
if [ $? -ne 0 ]; then | |
echo '获取软件包失败' >&2 | |
exit 1 | |
fi | |
tar --overwrite -xzf "$CLOUDDRIVE_SELECTED_ASSET" | |
ln -sf "$(pwd)/${CLOUDDRIVE_SELECTED_ASSET%.*}" clouddrive.d | |
# NOTE 因为在我的 openwrt 上 pgrep 没有 -u 选项 😂 | |
if pgrep -u $USER a &>/dev/null; then | |
pgrep_arr=(pgrep -u $USER) | |
else | |
pgrep_arr=(pgrep) | |
fi | |
echo | |
if [ $EUID -eq 0 ]; then | |
prep=() | |
else | |
prep=(sudo) | |
fi | |
case $(basename "$SYSTEM_INIT") in | |
'launchd') | |
if [ $EUID -eq 0 ]; then | |
service=clouddrive | |
else | |
service=clouddrive-$USER | |
fi | |
service_file="$HOME/Library/LaunchAgents/$service.plist" | |
mkdir -p "$HOME/Library/LaunchAgents" | |
echo $'\x1b[38;5;2m\x1b[1mCreated service file\x1b[0m:' "$service_file" | |
echo $'\x1b[38;5;2m\x1b[1m>>>\x1b[0m' | |
tee "$service_file" << EOF | |
<?xml version="1.0" encoding="UTF-8"?> | |
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> | |
<plist version="1.0"> | |
<dict> | |
<key>Description</key> | |
<string>CloudDrive - 解锁云存储的无限可能</string> | |
<key>Documentation</key> | |
<string>http://www.clouddrive2.com/help.html</string> | |
<key>Label</key> | |
<string>com.clouddrive</string> | |
<key>UserName</key> | |
<string>$USER</string> | |
<key>KeepAlive</key> | |
<true /> | |
<key>ProgramArguments</key> | |
<array> | |
<string>/bin/sh</string> | |
<string>-c</string> | |
<string>'$HOME/clouddrive.d/clouddrive'</string> | |
</array> | |
<key>RunAtLoad</key> | |
<true /> | |
<key>OnDemand</key> | |
<false /> | |
<key>LaunchOnlyOnce</key> | |
<true /> | |
<key>StandardErrorPath</key> | |
<string>/tmp/$service.err</string> | |
<key>StandardOutPath</key> | |
<string>/tmp/$service.out</string> | |
</dict> | |
</plist> | |
EOF | |
if [ $? -eq 0 ]; then | |
echo $'\x1b[38;5;2m\x1b[1m<<<\x1b[0m' | |
echo $'\x1b[38;5;2m\x1b[1mSTART service\x1b[0m:' "launchctl load -w '$service_file'" | |
echo $'\x1b[38;5;2m\x1b[1mSTOP service\x1b[0m:' "launchctl unload '$service_file'" | |
launchctl unload "$service_file" 2>&- | |
launchctl load -w "$service_file" | |
fi | |
;; | |
'systemd') | |
if [ $EUID -eq 0 ]; then | |
service=clouddrive | |
else | |
service=clouddrive-$USER | |
fi | |
service_file=/etc/systemd/system/$service.service | |
echo $'\x1b[38;5;2m\x1b[1mCreated service file\x1b[0m:' "$service_file" | |
echo $'\x1b[38;5;2m\x1b[1m>>>\x1b[0m' | |
"${prep[@]}" tee "$service_file" << EOF | |
[Unit] | |
Description='CloudDrive - 解锁云存储的无限可能' | |
Documentation='http://www.clouddrive2.com/help.html' | |
After=network.target | |
[Service] | |
Type=simple | |
User=$USER | |
Restart=on-failure | |
ExecStart='$HOME/clouddrive.d/clouddrive' | |
[Install] | |
WantedBy=default.target | |
EOF | |
if [ $? -eq 0 ]; then | |
echo $'\x1b[38;5;2m\x1b[1m<<<\x1b[0m' | |
echo $'\x1b[38;5;2m\x1b[1mSTART service\x1b[0m:' "service $service start" | |
echo $'\x1b[38;5;2m\x1b[1mSTOP service\x1b[0m:' "systemctl start $service" | |
echo $'\x1b[38;5;2m\x1b[1mSTART service\x1b[0m:' "service $service stop" | |
echo $'\x1b[38;5;2m\x1b[1mSTOP service\x1b[0m:' "systemctl stop $service" | |
"${prep[@]}" systemctl enable "$service" | |
"${prep[@]}" systemctl stop "$service" | |
"${prep[@]}" systemctl start "$service" | |
fi | |
;; | |
'init') | |
if [ $EUID -eq 0 ]; then | |
service=clouddrive | |
else | |
service=clouddrive-$USER | |
fi | |
service_file=/etc/init/$service.conf | |
echo $'\x1b[38;5;2m\x1b[1mCreated service file\x1b[0m:' "$service_file" | |
echo $'\x1b[38;5;2m\x1b[1m>>>\x1b[0m' | |
"${prep[@]}" tee "$service_file" << EOF | |
description "CloudDrive - 解锁云存储的无限可能" | |
documentation "http://www.clouddrive2.com/help.html" | |
start on filesystem or runlevel [2345] | |
stop on runlevel [!2345] | |
respawn | |
exec '$HOME/clouddrive.d/clouddrive' | |
EOF | |
if [ $? -eq 0 ]; then | |
echo $'\x1b[38;5;2m\x1b[1m<<<\x1b[0m' | |
echo $'\x1b[38;5;2m\x1b[1mSTART service\x1b[0m:' "service $service start" | |
echo $'\x1b[38;5;2m\x1b[1mSTOP service\x1b[0m:' "service $service stop" | |
"${prep[@]}" service "$service" enable | |
"${prep[@]}" service "$service" stop | |
"${prep[@]}" service "$service" start | |
fi | |
;; | |
'procd') | |
if [ $EUID -eq 0 ]; then | |
service=clouddrive | |
else | |
service=clouddrive-$USER | |
fi | |
service_file=/etc/init.d/$service | |
echo $'\x1b[38;5;2m\x1b[1mCreated service file\x1b[0m:' "$service_file" | |
echo $'\x1b[38;5;2m\x1b[1m>>>\x1b[0m' | |
"${prep[@]}" tee "$service_file" << EOF | |
#!/bin/sh /etc/rc.common | |
USE_PROCD=1 | |
START=99 | |
STOP=99 | |
Description='CloudDrive - 解锁云存储的无限可能' | |
Documentation='http://www.clouddrive2.com/help.html' | |
start_service() { | |
procd_open_instance | |
procd_set_param command '$HOME/clouddrive.d/clouddrive' | |
procd_set_param respawn | |
procd_set_param user $USER | |
procd_set_param stdout 1 | |
procd_set_param stderr 1 | |
procd_set_param pidfile /var/run/clouddrive-$USER.pid | |
procd_close_instance | |
} | |
EOF | |
if [ $? -eq 0 ]; then | |
echo $'\x1b[38;5;2m\x1b[1m<<<\x1b[0m' | |
"${prep[@]}" chmod +x "$service_file" | |
echo $'\x1b[38;5;2m\x1b[1mSTART service\x1b[0m:' "service $service start" | |
echo $'\x1b[38;5;2m\x1b[1mSTOP service\x1b[0m:' "service $service stop" | |
"${prep[@]}" service "$service" enable | |
"${prep[@]}" service "$service" stop | |
"${prep[@]}" service "$service" start | |
fi | |
;; | |
*) # 默认情况 | |
echo $'\x1b[38;5;2m\x1b[1mSTART service\x1b[0m:' "'$HOME/clouddrive.d/clouddrive' &" | |
echo $'\x1b[38;5;2m\x1b[1mSTOP service\x1b[0m:' "${pgrep_arr[@]} clouddrive | xargs kill -9" | |
# NOTE 如果有已经运行的实例,终结之 | |
"${pgrep_arr[@]}" clouddrive | xargs kill -9 | |
"$HOME/clouddrive.d/clouddrive" & | |
;; | |
esac | |
echo | |
echo -e '\x1b[38;5;3mDocumentation\x1b[0m: http://www.clouddrive2.com/help.html' | |
echo -e "\x1b[38;5;3mServer on\x1b[0m: http://$(get-local-ipv4-select):19798" | |
echo '### 测试账号 ###' | |
echo 'mail: test@test.com' | |
echo 'password: 123456' |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env bash | |
echo "Step 1: 安装 AList" | |
apt update | |
apt install -y alist jq wget | |
echo "Step 2: 设置自启动" | |
wget -q https://gist.githubusercontent.com/ChenyangGao/e8e520de651e6375dad552b5a761902f/raw/alist.sh -O ~/alist.sh | |
chmod +x ~/alist.sh | |
~/alist.sh enable | |
~/alist.sh start -d | |
echo "Step 3: 修改 admin 的密码为 123456" | |
alist admin set 123456 | |
echo "Step 4: 启用 guest 用户,免密码、启用 Webdav、只读" | |
AlistToken=$(wget -q -O - --header="Content-Type: application/json" --post-data='{"username": "admin", "password": "123456"}' http://localhost:5244/api/auth/login | jq -r '.data.token') | |
wget -q -O - --header="Content-Type: application/json" --header "Authorization: $AlistToken" --post-data='{"id": 2, "username": "guest", "password": "", "role": 1, "permission": 258, "disabled": false}' http://localhost:5244/api/admin/user/update |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Termux 是 Android 平台上的一个终端模拟器和开发环境,由于没有类似 systemd 之类的进程管理器,所以想要自启动需要一些其他的办法。
下面是我想出的一种办法,可以在当前 shell 的 rc 文件中写入一段启动脚本实现开启 Termux 就自动运行 alist 和 clouddrive。
参见上面的
alist.sh
和clouddrive.sh
。本 gist 是这篇文章的代码部分:https://chenyanggao.github.io/2023/08/02/14.%E5%9C%A8Linux:MacOSX%E4%B8%8A%E9%83%A8%E7%BD%B2AList%E5%92%8Cclouddrive/
👊 可以用下面的脚本实现伴随 Termux 打开后的自动启动 alist:
bash -c "$(wget -q -O - https://gist.githubusercontent.com/ChenyangGao/e8e520de651e6375dad552b5a761902f/raw/termux-init-alist.sh)"