#!/usr/bin/env bash ## 文件路径、脚本网址、文件版本以及各种环境的判断 ShellDir=${JD_DIR:-$(cd $(dirname $0); pwd)} [[ ${JD_DIR} ]] && ShellJd=jd || ShellJd=${ShellDir}/jd.sh LogDir=${ShellDir}/log [ ! -d ${LogDir} ] && mkdir -p ${LogDir} ScriptsDir=${ShellDir}/scripts Scripts2Dir=${ShellDir}/scripts2 ConfigDir=${ShellDir}/config FileConf=${ConfigDir}/config.sh FileDiy=${ConfigDir}/diy.sh FileConfSample=${ShellDir}/sample/config.sh.sample ListCron=${ConfigDir}/crontab.list ListCronLxk=${ScriptsDir}/docker/crontab_list.sh ListCronShylocks=${Scripts2Dir}/docker/crontab_list.sh ListTask=${LogDir}/task.list ListJs=${LogDir}/js.list ListJsAdd=${LogDir}/js-add.list ListJsDrop=${LogDir}/js-drop.list ContentVersion=${ShellDir}/version ContentNewTask=${ShellDir}/new_task ContentDropTask=${ShellDir}/drop_task SendCount=${ShellDir}/send_count isTermux=${ANDROID_RUNTIME_ROOT}${ANDROID_ROOT} ShellURL=${JD_SHELL_URL:-git@gitee.com:evine/jd_shell.git} ScriptsURL=${JD_SCRIPTS_URL:-git@gitee.com:lxk0301/jd_scripts.git} ## 导入配置文件 function Import_Conf { if [ -f ${FileConf} ]; then . ${FileConf} fi } ## 更新crontab,gitee服务器同一时间限制5个链接,因此每个人更新代码必须错开时间,每次执行git_pull随机生成。 ## 每天次数随机,更新时间随机,更新秒数随机,至少6次,至多12次,大部分为8-10次,符合正态分布。 function Update_Cron { if [[ $(date "+%-H") -le 2 ]] && [ -f ${ListCron} ]; then RanMin=$((${RANDOM} % 60)) RanSleep=$((${RANDOM} % 56)) RanHourArray[0]=$((${RANDOM} % 3)) for ((i=1; i<14; i++)); do j=$(($i - 1)) tmp=$((${RANDOM} % 3 + ${RanHourArray[j]} + 2)) [[ ${tmp} -lt 24 ]] && RanHourArray[i]=${tmp} || break done RanHour=${RanHourArray[0]} for ((i=1; i<${#RanHourArray[*]}; i++)); do RanHour="${RanHour},${RanHourArray[i]}" done perl -i -pe "s|.+(bash.+git_pull.+log.*)|${RanMin} ${RanHour} \* \* \* sleep ${RanSleep} && \1|" ${ListCron} crontab ${ListCron} fi } ## 重置仓库remote url function Reset_RepoUrl { if [[ ${JD_DIR} ]] && [[ ${ENABLE_RESET_REPO_URL} == true ]]; then if [ -d ${ShellDir}/.git ]; then cd ${ShellDir} git remote set-url origin ${ShellURL} git reset --hard fi if [ -d ${ScriptsDir}/.git ]; then cd ${ScriptsDir} git remote set-url origin ${ScriptsURL} git reset --hard fi fi } ## 更新shell function Git_PullShell { echo -e "更新shell...\n" cd ${ShellDir} git fetch --all ExitStatusShell=$? git reset --hard origin/master echo } ## 更新shell成功后的操作 function Git_PullShellNext { if [[ ${ExitStatusShell} -eq 0 ]]; then echo -e "更新shell成功...\n" Update_Entrypoint [[ "${PanelDependOld}" != "${PanelDependNew}" ]] && cd ${ShellDir}/panel && Npm_Install panel cp -f ${FileConfSample} ${ConfigDir}/config.sh.sample [ -d ${ScriptsDir}/node_modules ] && Notify_Version else echo -e "更新shell失败,请检查原因...\n" fi } ## 克隆scripts function Git_CloneScripts { echo -e "克隆scripts...\n" git clone -b master ${ScriptsURL} ${ScriptsDir} ExitStatusScripts=$? echo } ## 更新scripts function Git_PullScripts { echo -e "更新scripts...\n" cd ${ScriptsDir} git fetch --all ExitStatusScripts=$? git reset --hard origin/master echo } ## 更新docker-entrypoint function Update_Entrypoint { if [[ ${JD_DIR} ]] && [[ $(cat ${ShellDir}/docker/docker-entrypoint.sh) != $(cat /usr/local/bin/docker-entrypoint.sh) ]]; then cp -f ${ShellDir}/docker/docker-entrypoint.sh /usr/local/bin/docker-entrypoint.sh chmod 777 /usr/local/bin/docker-entrypoint.sh fi } ## 用户数量UserSum function Count_UserSum { i=1 while [ $i -le 1000 ]; do Tmp=Cookie$i CookieTmp=${!Tmp} [[ ${CookieTmp} ]] && UserSum=$i || break let i++ done } ## 检测文件:LXK9301/jd_scripts 仓库中的 docker/crontab_list.sh ## 检测定时任务是否有变化,此函数会在Log文件夹下生成四个文件,分别为: ## task.list crontab.list中的所有任务清单,仅保留脚本名 ## js.list 上述检测文件中用来运行js脚本的清单(去掉后缀.js,非运行脚本的不会包括在内) ## js-add.list 如果上述检测文件增加了定时任务,这个文件内容将不为空 ## js-drop.list 如果上述检测文件删除了定时任务,这个文件内容将不为空 function Diff_Cron { if [ -f ${ListCron} ]; then if [ -n "${JD_DIR}" ] then grep -E " j[drx]_\w+" ${ListCron} | perl -pe "s|.+ (j[drx]_\w+).*|\1|" | sort -u > ${ListTask} else grep "${ShellDir}/" ${ListCron} | grep -E " j[drx]_\w+" | perl -pe "s|.+ (j[drx]_\w+).*|\1|" | sort -u > ${ListTask} fi cat ${ListCronLxk} | grep -E "j[drx]_\w+\.js" | perl -pe "s|.+(j[drx]_\w+)\.js.+|\1|" | sort -u > ${ListJs} grep -vwf ${ListTask} ${ListJs} > ${ListJsAdd} grep -vwf ${ListJs} ${ListTask} > ${ListJsDrop} else echo -e "${ListCron} 文件不存在,请先定义你自己的crontab.list...\n" fi } ## 发送删除失效定时任务的消息 function Notify_DropTask { cd ${ShellDir} node update.js [ -f ${ContentDropTask} ] && rm -f ${ContentDropTask} } ## 发送新的定时任务消息 function Notify_NewTask { cd ${ShellDir} node update.js [ -f ${ContentNewTask} ] && rm -f ${ContentNewTask} } ## 检测配置文件版本 function Notify_Version { ## 识别出两个文件的版本号 VerConfSample=$(grep " Version: " ${FileConfSample} | perl -pe "s|.+v((\d+\.?){3})|\1|") [ -f ${FileConf} ] && VerConf=$(grep " Version: " ${FileConf} | perl -pe "s|.+v((\d+\.?){3})|\1|") ## 删除旧的发送记录文件 [ -f "${SendCount}" ] && [[ $(cat ${SendCount}) != ${VerConfSample} ]] && rm -f ${SendCount} ## 识别出更新日期和更新内容 UpdateDate=$(grep " Date: " ${FileConfSample} | awk -F ": " '{print $2}') UpdateContent=$(grep " Update Content: " ${FileConfSample} | awk -F ": " '{print $2}') ## 如果是今天,并且版本号不一致,则发送通知 if [ -f ${FileConf} ] && [[ "${VerConf}" != "${VerConfSample}" ]] && [[ ${UpdateDate} == $(date "+%Y-%m-%d") ]] then if [ ! -f ${SendCount} ]; then echo -e "检测到配置文件config.sh.sample有更新\n\n更新日期: ${UpdateDate}\n当前版本: ${VerConf}\n新的版本: ${VerConfSample}\n更新内容: ${UpdateContent}\n更新说明: 如需使用新功能请对照config.sh.sample,将相关新参数手动增加到你自己的config.sh中,否则请无视本消息。本消息只在该新版本配置文件更新当天发送一次。" | tee ${ContentVersion} cd ${ShellDir} node update.js if [ $? -eq 0 ]; then echo "${VerConfSample}" > ${SendCount} [ -f ${ContentVersion} ] && rm -f ${ContentVersion} fi fi else [ -f ${ContentVersion} ] && rm -f ${ContentVersion} [ -f ${SendCount} ] && rm -f ${SendCount} fi } ## npm install 子程序,判断是否为安卓,判断是否安装有yarn function Npm_InstallSub { if [ -n "${isTermux}" ] then npm install --no-bin-links || npm install --no-bin-links --registry=https://registry.npm.taobao.org elif ! type yarn >/dev/null 2>&1 then npm install || npm install --registry=https://registry.npm.taobao.org else echo -e "检测到本机安装了 yarn,使用 yarn 替代 npm...\n" yarn install || yarn install --registry=https://registry.npm.taobao.org fi } ## npm install function Npm_Install { echo -e "检测到 $1 的依赖包有变化,运行 npm install...\n" Npm_InstallSub if [ $? -ne 0 ]; then echo -e "\nnpm install 运行不成功,自动删除 $1/node_modules 后再次尝试一遍..." rm -rf node_modules fi echo if [ ! -d node_modules ]; then echo -e "运行 npm install...\n" Npm_InstallSub if [ $? -ne 0 ]; then echo -e "\nnpm install 运行不成功,自动删除 $1/node_modules...\n" echo -e "请进入 $1 目录后手动运行 npm install...\n" echo -e "3...\n" sleep 1 echo -e "2...\n" sleep 1 echo -e "1...\n" sleep 1 rm -rf node_modules fi fi } ## 输出是否有新的定时任务 function Output_ListJsAdd { if [ -s ${ListJsAdd} ]; then echo -e "检测到有新的定时任务:\n" cat ${ListJsAdd} echo fi } ## 输出是否有失效的定时任务 function Output_ListJsDrop { if [ ${ExitStatusScripts} -eq 0 ] && [ -s ${ListJsDrop} ]; then echo -e "检测到有失效的定时任务:\n" cat ${ListJsDrop} echo fi } ## 自动删除失效的脚本与定时任务,需要5个条件:1.AutoDelCron 设置为 true;2.正常更新js脚本,没有报错;3.js-drop.list不为空;4.crontab.list存在并且不为空;5.已经正常运行过npm install ## 检测文件:LXK9301/jd_scripts 仓库中的 docker/crontab_list.sh ## 如果检测到某个定时任务在上述检测文件中已删除,那么在本地也删除对应定时任务 function Del_Cron { if [ "${AutoDelCron}" = "true" ] && [ -s ${ListJsDrop} ] && [ -s ${ListCron} ] && [ -d ${ScriptsDir}/node_modules ]; then echo -e "开始尝试自动删除定时任务如下:\n" cat ${ListJsDrop} echo JsDrop=$(cat ${ListJsDrop}) for Cron in ${JsDrop} do perl -i -ne "{print unless / ${Cron}( |$)/}" ${ListCron} done crontab ${ListCron} echo -e "成功删除失效的脚本与定时任务,当前的定时任务清单如下:\n\n--------------------------------------------------------------\n" crontab -l echo -e "\n--------------------------------------------------------------\n" if [ -d ${ScriptsDir}/node_modules ]; then echo -e "删除失效的定时任务:\n\n${JsDrop}" > ${ContentDropTask} Notify_DropTask fi fi } ## 自动增加新的定时任务,需要5个条件:1.AutoAddCron 设置为 true;2.正常更新js脚本,没有报错;3.js-add.list不为空;4.crontab.list存在并且不为空;5.已经正常运行过npm install ## 检测文件:LXK9301/jd_scripts 仓库中的 docker/crontab_list.sh ## 如果检测到检测文件中增加新的定时任务,那么在本地也增加 ## 本功能生效时,会自动从检测文件新增加的任务中读取时间,该时间为北京时间 function Add_Cron { if [ "${AutoAddCron}" = "true" ] && [ -s ${ListJsAdd} ] && [ -s ${ListCron} ] && [ -d ${ScriptsDir}/node_modules ]; then echo -e "开始尝试自动添加定时任务如下:\n" cat ${ListJsAdd} echo JsAdd=$(cat ${ListJsAdd}) for Cron in ${JsAdd} do if [[ ${Cron} == jd_bean_sign ]] then echo "4 0,9 * * * bash ${ShellJd} ${Cron}" >> ${ListCron} else cat ${ListCronLxk} | grep -E "\/${Cron}\." | perl -pe "s|(^.+)node */scripts/(j[drx]_\w+)\.js.+|\1bash ${ShellJd} \2|" >> ${ListCron} fi done if [ $? -eq 0 ] then crontab ${ListCron} echo -e "成功添加新的定时任务,当前的定时任务清单如下:\n\n--------------------------------------------------------------\n" crontab -l echo -e "\n--------------------------------------------------------------\n" if [ -d ${ScriptsDir}/node_modules ]; then echo -e "成功添加新的定时任务:\n\n${JsAdd}" > ${ContentNewTask} Notify_NewTask fi else echo -e "添加新的定时任务出错,请手动添加...\n" if [ -d ${ScriptsDir}/node_modules ]; then echo -e "尝试自动添加以下新的定时任务出错,请手动添加:\n\n${JsAdd}" > ${ContentNewTask} Notify_NewTask fi fi fi } ## 在日志中记录时间与路径 echo -e "\n--------------------------------------------------------------\n" echo -n "系统时间:" echo $(date "+%Y-%m-%d %H:%M:%S") if [ "${TZ}" = "UTC" ]; then echo echo -n "北京时间:" echo $(date -d "8 hour" "+%Y-%m-%d %H:%M:%S") fi echo -e "\nJS脚本目录:${ScriptsDir}\n" echo -e "--------------------------------------------------------------\n" ## 导入配置,更新cron,设置url,更新shell,复制sample,复制entrypoint,发送新配置通知 Import_Conf "git_pull" Update_Cron Reset_RepoUrl [ -f ${ShellDir}/panel/package.json ] && PanelDependOld=$(cat ${ShellDir}/panel/package.json) Git_PullShell [ -f ${ShellDir}/panel/package.json ] && PanelDependNew=$(cat ${ShellDir}/panel/package.json) Git_PullShellNext ## 克隆或更新js脚本 [ -f ${ScriptsDir}/package.json ] && ScriptsDependOld=$(cat ${ScriptsDir}/package.json) [ -d ${ScriptsDir}/.git ] && Git_PullScripts || Git_CloneScripts [ -f ${ScriptsDir}/package.json ] && ScriptsDependNew=$(cat ${ScriptsDir}/package.json) ## 执行各函数 if [[ ${ExitStatusScripts} -eq 0 ]] then echo -e "更新scripts成功...\n" Diff_Cron [[ "${ScriptsDependOld}" != "${ScriptsDependNew}" ]] && cd ${ScriptsDir} && Npm_Install scripts Output_ListJsAdd Output_ListJsDrop Del_Cron Add_Cron else echo -e "更新scripts失败,请检查原因...\n" fi ## 调用用户自定义的diy.sh if [[ ${EnableExtraShell} == true ]]; then if [ -f ${FileDiy} ] then . ${FileDiy} else echo -e "${FileDiy} 文件不存在,跳过执行DIY脚本...\n" fi fi