1 @ECHO OFF
  2 IF %1.==/?. GOTO Help
  3 IF %1.==/h. GOTO Help
  4 IF %1.==-?. GOTO Help
  5 IF %1.==-h. GOTO Help
  6 IF %1.==--help. GOTO Help
  7 GOTO Start
  8 
  9 :Help
 10 ECHO ^+----------------------------------------------------------------------------^+
 11 ECHO ^|                                                                            ^|
 12 ECHO ^| AutoUpdateSoftOnSkycn.cmd v0.2                                             ^|
 13 ECHO ^|                                                                            ^|
 14 ECHO ^| 此脚本用于自动从天空软件站(http://www.skycn.com)上下载指定软件的当前版本   ^|
 15 ECHO ^| (新版本),可以用来方便的追踪指定软件的新版本。                             ^|
 16 ECHO ^|                                                                            ^|
 17 ECHO ^| 使用方法: 在 ItemIDList 文件中添加需要下载的软件的 ID,一行一个 ID。软件的 ^|
 18 ECHO ^| ID 是指其下载页面的文件名。比如腾讯QQ/TM 2005 珊瑚虫外挂的下载页面 URL 是  ^|
 19 ECHO ^| http://www.skycn.com/soft/14096.html,那么它的 ID 就是 14096^|
 20 ECHO ^|                                                                            ^|
 21 ECHO ^| AutoUpdateSoftOnSkycn [Option1=Value1] [Option2=Value2] ...                ^|
 22 ECHO ^|                                                                            ^|
 23 ECHO ^| 选项列表请参阅配置文件 AUSOS.conf                                          ^|
 24 ECHO ^|                                                                            ^|
 25 ECHO ^| 此脚本需要以下 GNU 命令行工具:                                             ^|
 26 ECHO ^|     grep                                                                   ^|
 27 ECHO ^|     sed                                                                    ^|
 28 ECHO ^|     sleep                                                                  ^|
 29 ECHO ^|     wget                                                                   ^|
 30 ECHO ^| 可以通过安装 Cygwin(http://www.cygwin.com)获得这些工具(推荐给 Linux 爱好者 ^|
 31 ECHO ^| 和有经验的用户)。不要使用 GnuWin32(http://gnuwin32.sourceforge.net)中的这  ^|
 32 ECHO ^| 些工具,因为其中的 grep 和 sed 都存在 bug。                                ^|
 33 ECHO ^|                                                                            ^|
 34 ECHO ^| 此外,如果没有 Cygwin 中的 unix2dos 程序,“记事本”将无法正常显示由此脚自 ^|
 35 ECHO ^| 动修改过的 ItemIDList 文件。此时,除了 Vim、Emacs、EditPlus、UltraEdit 等  ^|
 36 ECHO ^| 常见的文本编辑器外,也可以使用 Windows 自带的“写字板”来编辑它。          ^|
 37 ECHO ^|                                                                            ^|
 38 ECHO ^| Creator: Rainux                                                            ^|
 39 ECHO ^| URL: http://www.rainux.org                                                 ^|
 40 ECHO ^|                                                                            ^|
 41 ECHO ^+----------------------------------------------------------------------------^+
 42 REM TODO:
 43 REM     通用化,使其易于扩展
 44 REM     增加软件类别设置
 45 REM     Port to bash script
 46 REM     检测 grep 等工具是否是 GNU 版本
 47 REM
 48 REM Last change: 2006 Jan 04
 49 GOTO End
 50 
 51 :Start
 52 REM --------------------------------------------------------------------------
 53 SETLOCAL
 54 REM 软件 ID 列表文件
 55 SET ItemIDList="ItemIDList.ini"
 56 REM 镜像服务器名称(不要加“下载”二字)
 57 SET MirrorServer=广东佛山
 58 REM 下载文件存放目录
 59 SET DownloadPath="D:\Software Collection"
 60 REM 是否存放到单独目录
 61 SET SaveSeprt=YES
 62 REM 是否在文件名前添加软件名称(不建议使用,因为无法保留文件在服务器上的时间戳)
 63 SET UseFullName=NO
 64 REM 是否自动删除旧版本
 65 SET DelOld=YES
 66 REM 是否显示详细下载信息(如果禁用将无法看到 wget 下载文件的进度条)
 67 SET Verbose=YES
 68 REM 日志文件名(如果不设置,将使用标准输出)
 69 SET LogFile=
 70 REM 下载遇到严重错误时的重试次数,严重错误目前仅指 HTTP 403
 71 SET TryOnFatalError=32
 72 REM 下载遇到严重错误时重试的间隔时间(秒)
 73 SET WaitRetry=5
 74 REM 重试间隔时间的增量(秒)
 75 SET WaitIncrement=5
 76 REM 跳过下载测试,直接开始下载(不建议使用,除非确信不会遇到 HTTP 404 之类的情况,
 77 REM 因为如果遇到无法下载的文件,将会把很长的时间浪费在毫无意义的重复累加等待上)
 78 SET SkipTest=NO
 79 REM Wget 使用的参数
 80 SET WgetArgs=--no-cache -c -N -t0 --waitretry=10
 81 REM
 82 REM --------------------------------------------------------------------------
 83 REM 覆盖用户环境变量设置
 84 REM
 85 REM 防止 Cygwin 里的程序在 NTFS 卷上创建文件时修改文件的默认访问权限
 86 SET CYGWIN=nontsec
 87 REM
 88 REM --------------------------------------------------------------------------
 89 REM 声明全局变量
 90 SET ID=id
 91 SET ItemName=itemname
 92 SET FileName=filename
 93 SET Referer=referer
 94 SET Logger=logger
 95 SET RealWaitRetry=0
 96 REM 临时文件名
 97 SET AUSOS1="%TEMP%\AUSOS1.tmp"
 98 SET AUSOS2="%TEMP%\AUSOS2.tmp"
 99 SET AUSOSfile="%TEMP%\AUSOSfile.tmp"
100 SET AUSOSname="%TEMP%\AUSOSname.tmp"
101 SET AUSOSurl="%TEMP%\AUSOSurl.tmp"
102 SET AUSOSwgetlog="%TEMP%\AUSOSwgetlog.tmp"
103 REM --------------------------------------------------------------------------
104 
105 REM Collect user's options
106 IF EXIST "AUSOS.conf" (
107     FOR /F "usebackq eol=# tokens=1* delims==" %%i IN ("AUSOS.conf") DO (
108         SET %%i=%%j
109     )
110 )
111 :Loop
112     IF %1.==. GOTO EndLoop
113     IF %2.==. GOTO EndLoop
114     SET %1=%2
115     SHIFT
116     SHIFT
117     GOTO Loop
118 :EndLoop
119 
120 REM If LogFile not specified, not use Logger
121 FOR /F "tokens=*" %%f IN ("%LogFile%") DO (
122     SET LogFile="%%~ff"
123 )
124 IF %LogFile%.==. (
125     SET Logger=
126 ) ELSE (
127     REM Use Logger, set wget to no-verbose mode to disable the progress bar
128     DEL /F %LogFile% 2>NUL
129     SET Logger=^>^>%LogFile% 2^>^&1
130     SET WgetArgs=%WgetArgs% -nv
131 )
132 
133 REM Use the GNU tools in current directory first
134 FOR /F "tokens=*" %%i IN ("RNX") DO (
135     SET PATH="%%~dpi";%PATH%
136 )
137 
138 IF NOT EXIST %ItemIDList% (
139     ECHO 请先创建 ItemIDList 文件,在命令行带参数 -h 运行此脚本以查看帮助
140     GOTO End
141 )
142 IF NOT EXIST %DownloadPath% MD %DownloadPath%
143 FOR /F "usebackq eol=# tokens=1,2* delims=      " %%i IN (%ItemIDList%) DO (
144     REM %%i=ID; %%j=OldItemName; %%k=OldFileName
145     SET ID=%%i
146     wget -q --no-cache -O%AUSOS1% "http://www.skycn.com/soft/%%i.html"
147     REM Get the name of the downloading software
148     grep -i "<title>" %AUSOS1% > %AUSOSname%
149     REM Since sed's in-place edit can not work with the file not in current volume
150     PUSHD %TEMP%
151     sed -i "s/\(<title>\)\(.*\)\( - 天空软件站.*\)/\2/g" %AUSOSname%
152     REM Replace the special character which can not be used as file name to _
153     sed -i "s/[?""/\<>*|:]/_/g" %AUSOSname%
154     REM Replace space with .
155     sed -i "s/\s/\./g" %AUSOSname%
156     POPD
157     FOR /F "usebackq tokens=*" %%n IN (%AUSOSname%) DO (
158         SET %ItemName%=%%n
159         REM Get the URL and file name of the downloading software
160         grep -i "<a href[^<]*%MirrorServer%" %AUSOS1% > %AUSOS2%
161         sed "s/下载/\n/g" %AUSOS2% | grep "%MirrorServer%" | grep -i -o "http://[^']*" > %AUSOSurl%
162         grep -o "[^/]*$" %AUSOSurl% > %AUSOSfile%
163         FOR /F "usebackq tokens=*" %%f IN (%AUSOSfile%) DO (
164             SET %FileName%=%%f
165             REM Record the name of the downloading software, create a folder for it
166             FOR /F "tokens=*" %%p IN ("%ItemIDList%") DO (
167                 PUSHD %%~dpp
168                 sed -i "s/\(%%i\)\(.*\)/\1\t%%n\t%%f/g" %ItemIDList%
169                 unix2dos %ItemIDList% 2>NUL
170                 POPD
171             )
172             REM Delete old version if DelOld=YES and old name is present (%%j)
173             REM In this case, we assume user's options always the same
174             IF NOT "%%j"=="" (
175                 IF %DelOld%==YES (
176                     IF %SaveSeprt%==YES (
177                         IF NOT "%%j"=="%%n" (
178                             RD /S /Q %DownloadPath%\"%%j" 2>NUL
179                             ECHO 已删除旧版本软件 "%%j"%Logger%
180                         ) ELSE (
181                             REM If just file name changed
182                             IF NOT "%%k"=="%%f" (
183                                 IF %UseFullName%==YES (
184                                     DEL /F %DownloadPath%\"%%j"\"%%j"_"%%k" 2>NUL
185                                 ) ELSE (
186                                     DEL /F %DownloadPath%\"%%j"\"%%k" 2>NUL
187                                 )
188                                 ECHO 已删除 "%%j" 的旧版本文件 "%%k"%Logger%
189                             )
190                         )
191                     ) ELSE (
192                         REM If not save in separate directory and soft name changed
193                         IF NOT "%%j"=="%%n" (
194                             IF %UseFullName%==YES (
195                                 DEL /F %DownloadPath%\"%%j"_"%%k" 2>NUL
196                             ) ELSE (
197                                 DEL /F %DownloadPath%\"%%k" 2>NUL
198                             )
199                             ECHO 已删除旧版本软件 "%%j"%Logger%
200                         ) ELSE (
201                             REM If just file name changed
202                             IF NOT "%%k"=="%%f" (
203                                 IF %UseFullName%==YES (
204                                     DEL /F %DownloadPath%\"%%j"_"%%k" 2>NUL
205                                 ) ELSE (
206                                     DEL /F %DownloadPath%\"%%k" 2>NUL
207                                 )
208                                 ECHO 已删除 "%%j" 的旧版本文件 "%%k"%Logger%
209                             )
210                         )
211                     )
212                 )
213             )
214             REM Change current dir to file save dir
215             IF %SaveSeprt%==YES (
216                 MD %DownloadPath%\"%%n" 2>NUL
217                 PUSHD %DownloadPath%\"%%n"
218             ) ELSE (
219                 PUSHD %DownloadPath%
220             )
221             IF %UseFullName%==YES (
222                 SET OutFileName="%%n"_"%%f"
223             )
224             CALL :GetFile
225             POPD
226         )
227     )
228 )
229 
230 DEL /F %AUSOS1% 2>NUL
231 DEL /F %AUSOS2% 2>NUL
232 DEL /F %AUSOSfile% 2>NUL
233 DEL /F %AUSOSname% 2>NUL
234 DEL /F %AUSOSurl% 2>NUL
235 DEL /F %AUSOSwgetlog% 2>NUL
236 ENDLOCAL
237 
238 :End
239 GOTO :EOF
240 
241 REM --------------------------------------------------------------------------
242 REM TestGet:
243 REM     检查文件是否可以被下载,在遇到 HTTP 4xx 和 HTTP 5xx 状态时跳过下载
244 REM
245 :TestGet
246     SET Counter=0
247     SET RealWaitRetry=%WaitRetry%
248     :RetryTest
249         SET /A "Counter = Counter + 1"
250         ECHO 正在测试 "%FileName%" 是否可以下载%Logger%
251         wget -i%AUSOSurl% -o%AUSOSwgetlog% --spider %WgetArgs% --referer="http://www.skycn.com/soft/%ID%.html"
252         grep -q "HTTP.\+ 200 OK" %AUSOSwgetlog%
253         IF %ERRORLEVEL%==0 (
254             SET CanGet=True
255             GOTO EndTestGet
256         )
257         REM Stop retry on HTTP 4xx or HTTP 5xx except HTTP 403,
258         REM cause HTTP 403 often means server is busy
259         grep -q "HTTP.\+ 40[^3] .\+" %AUSOSwgetlog%
260         IF %ERRORLEVEL%==0 (
261             SET CanGet=False
262             GOTO EndTestGet
263         )
264         grep -q "HTTP.\+ 4[^0]\d .\+" %AUSOSwgetlog%
265         IF %ERRORLEVEL%==0 (
266             SET CanGet=False
267             GOTO EndTestGet
268         )
269         grep -q "HTTP.\+ 5\d\d .\+" %AUSOSwgetlog%
270         IF %ERRORLEVEL%==0 (
271             SET CanGet=False
272             GOTO EndTestGet
273         )
274         IF %Counter%==%TryOnFatalError% (
275             REM Log GetFile max fatal error reached
276             ECHO 测试下载 "%FileName%" 时遇到错误,已经达到允许的最大错误次数,测试失败%Logger%
277             SET CanGet=False
278             GOTO EndTestGet
279         )
280         ECHO 测试下载 "%FileName%" 时遇到错误,这是第 %Counter% 次出错,将在 %RealWaitRetry% 秒后重试%Logger%
281         sleep %RealWaitRetry%
282         SET /A "RealWaitRetry = RealWaitRetry + WaitIncrement"
283         GOTO RetryTest
284     SET CanGet=Unknown
285 :EndTestGet
286     IF %CanGet%==True (
287         ECHO 测试完成,"%FileName%" 可以下载%Logger%
288     ) ELSE (
289         ECHO 测试完成,"%FileName%" 无法下载,下载动作将被跳过%Logger%
290     )
291 GOTO :EOF
292 REM --------------------------------------------------------------------------
293 
294 REM --------------------------------------------------------------------------
295 REM GetFile:
296 REM     取得 %ItemName% 的文件 %FileName%
297 REM
298 :GetFile
299     IF %SkipTest%==NO (
300         CALL :TestGet
301     ) ELSE (
302         SET CanGet=True
303     )
304     IF NOT %CanGet%==True (
305         REM Log GetFile fail
306         GOTO EndGetFile
307     )
308     REM CAUTION: Must use "" to quote ItemName, cause if it have () will break the script
309     ECHO 开始下载 "%ItemName%",文件名为 "%FileName%"%Logger%
310     ECHO.%Logger%
311     REM Retry on download fail, e.g. HTTP 403
312     SET Counter=0
313     SET RealWaitRetry=%WaitRetry%
314     :RetryGet
315         SET /A "Counter = Counter + 1"
316         IF %UseFullName%==YES (
317             wget %WgetArgs% -i%AUSOSurl% -O%OutFileName% --referer="http://www.skycn.com/soft/%ID%.html"%Logger%
318         ) ELSE (
319             wget %WgetArgs% -i%AUSOSurl% --referer="http://www.skycn.com/soft/%ID%.html"%Logger%
320         )
321         IF %ERRORLEVEL%==0 (
322             REM Log GetFile success
323             ECHO "%ItemName%" 已经成功下载%Logger%
324             ECHO.%Logger%
325             GOTO EndGetFile
326         ) ELSE (
327             IF %Counter%==%TryOnFatalError% (
328                 REM Log GetFile max fatal error reached
329                 ECHO 下载 "%ItemName%" 时遇到错误,已经达到允许的最大错误次数,下载该文件失败%Logger%
330                 ECHO.%Logger%
331                 GOTO EndGetFile
332             )
333             ECHO 下载 "%ItemName%" 时遇到错误,这是第 %Counter% 次出错,将在 %RealWaitRetry% 秒后重试%Logger%
334             ECHO.%Logger%
335             sleep %RealWaitRetry%
336             SET /A "RealWaitRetry = RealWaitRetry + WaitIncrement"
337             GOTO RetryGet
338         )
339 :EndGetFile
340 REM --------------------------------------------------------------------------