tcdownload.cmd v1.2b - Downloads latest version of Total Commander

Discuss and announce Total Commander plugins, addons and other useful tools here, both their usage and their development.

Moderators: Hacker, petermad, Stefan2, white

User avatar
white
Power Member
Power Member
Posts: 6022
Joined: 2003-11-19, 08:16 UTC
Location: Netherlands

tcdownload.cmd v1.2b - Downloads latest version of Total Commander

Post by *white »

tcdownload.cmd is a batch file to download the latest version of Total Commander.

Characteristics are:
  • It uses curl, included in Windows 10 version 1803 or later.
  • It doesn't analyze Total Commander's website, but simply assumes the installers are at a fixed location on the server. If the position on the server changes, the tool needs to be adjusted.
  • You can specify whether to download final version/beta version, 32-bit/64-bit/combined installer, in various combinations.
  • Files that already exist locally, are not downloaded unless the /F parameter is used.
  • Parameter /DD cleans up duplicate installers after a download (or attempt to do so).
  • You can also specify a Total Commander version to download, but it is trial and error to see whether the installer for that version exists in the fixed location on the server (probably works for recent versions).
  • Use parameter /? for help, parameter /P adds a pause when the batch file ends.
Please test :)

Filename:

Code: Select all

tcdownload.cmd
Contents:

Code: Select all

@echo off

Rem
Rem  tcdownload.cmd v1.2b, by user white, Total Commander forum (https://www.ghisler.ch/board/)
Rem
Rem  Downloads latest version of Total Commander.
Rem  When beta testing is ongoing, the latest beta version can also be downloaded.
Rem
Rem  This tool doesn't check the website for updates, but uses the same method
Rem  as Total Commander for checking for updates. A new version may already be
Rem  available without this tool (or Total Commander) showing it. This tool may
Rem  detect a new version sooner though.
Rem
Rem  This tool assumes installers are at a fixed location on the server. If the
Rem  position on the server changes, downloads will fail and this tool need to
Rem  be adjusted (see URL masks below).
Rem
Rem  One way to use this tool, is to place this batch file in the downloads
Rem  folder and drag the file onto Total Commander's button bar. Edit the button
Rem  and add parameter /P (pause). If Total Commander reports that a newer
Rem  version is available, you can click the button to download Total Commander.
Rem
Rem  Use parameter /? for help.
Rem
Rem  Requirements
Rem    curl                 Included in Windows 10 version 1803 or later.
Rem    certutil -hashfile   Included in Window 7 or later.
Rem

:: Disable delayed expansion to allow "!" character in passed parameters
setlocal EnableExtensions DisableDelayedExpansion

:: Settings
:: Name and version of this tool
set "tool_name_and_version=TCDOWNLOAD v1.2b"
:: URLs for downloading TC, if the tool no longer works, check if the URLs need adjusting
set "mask_url_final=https://www.totalcommander.ch/[v_major][v_minor]/tcmd[v_major][v_minor][v_patch]x[bitness].exe"
set "mask_url_beta=https://www.totalcommander.ch/beta/tc[v_major][v_minor]x[bitness]_[v_bnumber].exe"
:: Codes for beta and release candidate used in remote filenames
set "code_beta=b"
set "code_rc=rc"
:: Default download folder (default: current folder)
set "default_download_folder="
:: Default download list for 64-bit Windows (to download all 6 installers by default use: 32 64 32_64 b32 b64 b32_64)
set "default_download_list_64=64"
:: Default download list for 32-bit Windows
set "default_download_list_32=32"
:: Force downloading if file already exists locally
set "flag_force_download="
:: Delete duplicates after downloading
set "flag_delete_duplicates="
:: Pause before the script ends (no pause if undefined)
set "flag_end_pause="
:: Command used to pause before the script ends
set "cmd_end_pause=echo:&pause"
:: Command used for determining the latest TC version
set "cmd_to_get_version=nslookup -type=TXT [version_domain] [dns_server] 2>nul"
:: Domain names configured with fake IPv4 addresses to hold latest version info
set "domain_final_version=releaseversion.ghisler.com"
set "domain_beta_version=releasebeta.ghisler.com"
:: Default DNS server used for nslookup (8.8.8.8 = dns.google)
set "default_dns_server=8.8.8.8"
:: Download program and parameters
set "download_program=curl.exe"
set "download_params=--silent --show-error --fail --location --output"
:: Command to create hash
set "cmd_create_hash=certutil -hashfile"
:: Hash algorithm used to check for duplicate files (together with file size)
set "dupchk_hash_algo=SHA256"
:: Hash length of used hash algorithm
set "dupchk_hash_length=64"
:: Messages and texts
set "msg_header=%tool_name_and_version%"
set "msg_latest_version=Latest final version : [version]"
set "msg_latest_bversion=Latest beta version  : [version]"
set "msg_flag_specified_version=Requested version : [version]"
set "msg_beta_not_available=> No beta for a new release is available at this time."
set "msg_download_file_exists1=Download: "
set "msg_download_file_exists2=. File already exists locally. Download skipped."
set "msg_downloading=Downloading "
set "msg_downloading_to1=Downloading "
set "msg_downloading_to2= to "
set "msg_deleting_duplicate=* Deleting duplicate file: "
set "error_invalid_param=Invalid parameter: "
set "error_no_download_folder=ERROR: Nonexistent or inaccessible folder: "
set "error_no_download_program=ERROR: 'curl' is not available. (Included in Windows 10 version 1803 or later.)"
set "error_final_unknown=ERROR: Cannot determine latest final version. Final version not downloaded."
set "error_beta_unknown=ERROR: Cannot determine latest beta version. Beta version not downloaded."
set "txt_help_header=Downloads latest Total Commander version."
set "txt_unknown_version=<unknown>"
set "txt_beta_not_available=<not available>"
set "txt_beta= beta "
set "txt_rc= release candidate "

goto :start_program

::
:: display_usage: Show usage information
::
:display_usage
echo:
echo TCDOWNLOAD [drive:][path] [/32] [/64] [/32_64] [/B32] [/B64] [/B32_64]
echo            [/ALL] [/ALLF] [/ALLB] [/F] [/DD] [/V:version] [dns_server] [/P] [/?]
echo:
echo   [drive:][path]  Specifies the download folder.
echo   [/32]           Download 32-bit final version.
echo   [/64]           Download 64-bit final version.
echo   [/32_64]        Download 32+64-bit final version.
echo   [/B32]          Download 32-bit beta version.
echo   [/B64]          Download 64-bit beta version.
echo   [/B32_64]       Download 32+64-bit beta version.
echo   [/ALL]          Same as [/32] [/64] [/32_64] [/B32] [/B64] [/B32_64].
echo   [/ALLF]         Same as [/32] [/64] [/32_64].
echo   [/ALLB]         Same as [/B32] [/B64] [/B32_64].
echo   [/F]            Force downloading if file already exists locally.
echo   [/DD]           Delete duplicate "filename (n).exe" installers via size and hash check.
echo   [/V:version]    Specifies version (e.g. /v:10.52, /v:11.00b1, /v:11.55rc7).
echo   dns_server      DNS server (IPv4) used for nslookup (default: 8.8.8.8 = dns.google)
echo   [/P]            Pause after execution.
echo   [/?]            Display help. Shows more help when combined with /DD or /V:version.
echo:
echo Parameters can be used in any order.
echo Note: Downloading the latest beta version is only available during active beta testing.
echo:
echo Default download: 32-bit final version on 32-bit Windows, 64-bit version otherwise.
echo Requirements:     Windows 10 version 1803 or later.
if defined flag_delete_duplicates (
	echo:
	echo The /DD switch deletes duplicate files after downloading a file. It scans for matching
	echo files with sequence number 0 to 99. It skips read-only, hidden, and system files.
	echo The file with no sequence number is kept, or the one with the lowest number.
	echo:
	echo Note that files that are deleted are not necessarily identical to each other. They may
	echo be identical to different remaining files.
)
if defined flag_version_param (
	echo:
	echo The /V:version option lets you download a specific final or beta release instead of
	echo the latest. This serves as a raw additional feature, since the tool's main purpose is
	echo fetching the latest version. It constructs the download URL from your version string
	echo using a fixed format; if no file exists at that URL, the download fails.
)
exit /b

:start_program

:: General steps done by the program:
:: * Parse parameters, set variables
:: * Show error or help text
:: * Show Total Commander version information
:: * Download the installer files

:: Parse parameters, set variables
set "script_folder=%~dp0"
set "v_major="
set "v_minor="
set "v_patch_letter="
set "bv_major="
set "bv_minor="
set "bv_beta_number="
set "exit_code=0"
set "download_folder="
set "download_list="
set "dns_server="
set "flag_help="
set "invalid_param="
set "flag_specified_version="
set "flag_version_param="
set "all_finals= 32 64 32_64 "
set "all_betas= b32 b64 b32_64 "
goto :start_parsing
:next_param
shift /1
:start_parsing
set "p=%~1"
if not defined p goto :parse_end
:: Remove quotes to prevent errors
set "p=%p:"=%"
if "%p:~0,1%"=="/" goto :check_named_params
:: Check for parameters dns server and download folder
if not defined dns_server (
	:: Scan first 16 characters for IPv4 address
	echo "%p:~0,15%_%p:~15,1%"|findstr /rc:"^\"[0-9][0-9]*\.[0-9][0-9]*\.[0-9][0-9]*\.[0-9][0-9]*_\"$" >nul
	if not errorlevel 1 call :check_ipv4 "%p%" && (set "dns_server=%p%" & goto :next_param)
)
:: Parameter is not dns server, so assume it is the download folder
if not defined download_folder set "download_folder=%p%" & goto :next_param
:check_named_params
for %%i in (%all_finals%%all_betas%) do (
	if /i "%p:~0,8%"=="/%%~i" set "download_list=%download_list% %%~i" & goto :next_param
)
if /i "%p:~0,5%"=="/all" set "download_list=%download_list%%all_finals%%all_betas%" & goto :next_param
if /i "%p:~0,6%"=="/allf" set "download_list=%download_list%%all_finals%" & goto :next_param
if /i "%p:~0,6%"=="/allb" set "download_list=%download_list%%all_betas%" & goto :next_param
if "%p:~0,3%"=="/?" set "flag_help=1" & goto :next_param
if /i "%p:~0,3%"=="/f" set "flag_force_download=1" & goto :next_param
if /i "%p:~0,4%"=="/dd" set "flag_delete_duplicates=1" & goto :next_param
if /i "%p:~0,3%"=="/v:" (
	set "flag_version_param=1"
	if not defined flag_specified_version (
		:: Check formatting and length of specified version (max 9 chars)
		echo "%p:~3,9%_%p:~12,1%"|findstr /rc:"^\"[0-9][0-9]*\.[0-9][0-9][0-9a-z]*_\"$" >nul
		if not errorlevel 1 (
			:: Parse specified version
			call :parse_version "%p:~3%" v_major v_minor v_patch_letter bv_major bv_minor bv_beta_number
			if not errorlevel 1 set "flag_specified_version=1" & goto :next_param
		)
	)
)
if /i "%p:~0,3%"=="/p" set "flag_end_pause=1" & goto :next_param
:: A parameter not parsed yet is an invalid parameter
if not defined invalid_param set "invalid_param=%p%" & goto :next_param
:parse_end

:: Parameters are stored, enable delayed expansion
setlocal EnableDelayedExpansion

:: Show help or error
if defined flag_help (
	echo !txt_help_header!
	call :display_usage
	goto :end_script
)
if defined invalid_param (
	echo !error_invalid_param!"!invalid_param!"
	call :display_usage
	goto :end_script
)

:: Use defaults if necessary
if not defined download_folder set "download_folder=!default_download_folder!"
if not defined download_list (
	set "download_list=!default_download_list_64!"
	if "%processor_architecture%"=="x86" if not defined processor_architew6432 (
		set "download_list=!default_download_list_32!"
	)
)
if not defined dns_server set "dns_server=!default_dns_server!"

:: Change current folder to the download folder
if defined download_folder pushd "!download_folder!" 2>nul
If %errorlevel% NEQ 0 (
	echo !error_no_download_folder!"!download_folder!"
	goto :end_script
)

:: Check if download program is available
if not defined download_program goto :download_program_not_found
if exist "!download_program!" goto :download_program_found
:strip_folder
set "download_program=!download_program:*\=!"
if not defined download_program (
	goto :download_program_not_found
) else (
	if not "!download_program!"=="!download_program:\=!" goto :strip_folder
)
:: Check in the paths specified by the PATH environment variable
where /q "!download_program!" && goto :download_program_found
:: Search for download program within the script folder
set "found_program="
:: Disable delayed expansion to disable expansion of ^ and ! characters in %%f
setlocal DisableDelayedExpansion
for /f "eol= delims=" %%f in ('where /r "%script_folder%." "%download_program%" 2^>nul') do (
	if not defined found_program set "found_program=%%~f"
)
if defined found_program set "found_program=%found_program:^=^^%"
if defined found_program set "found_program=%found_program:!=^!%"
endlocal & set "found_program=%found_program%"
if defined found_program set "download_program=!found_program!" & goto:download_program_found
:download_program_not_found
echo !error_no_download_program!
goto :end_script
:download_program_found

:: Get version info if no version specified
if defined flag_specified_version goto :end_retrieving_version_info
:: Fill in DNS server in command to get version info
set "cmd_to_get_version=!cmd_to_get_version:[dns_server]=%dns_server%!"
:: Get final version info
set "v_patch_num="
set "cmd=!cmd_to_get_version:[version_domain]=%domain_final_version%!"
:: Get tokens after the first 4 lines of the output
for /f "skip=4 tokens=2,3,4 delims=.;" %%a in ('"!cmd!"') do if not defined v_patch_num (
	set "v_major=%%a"
	set "v_minor=%%b"
	set "v_patch_num=%%c"
)
:: Convert patch number to patch letter (0="", 1=a, 2=b, etc.)
if defined v_patch_num (
	set "letters=_abcdefghijklmnopqrstuvwxyz"
	set "v_patch_letter=!letters:~%v_patch_num%,1!"
	set "v_patch_letter=!v_patch_letter:_=!"
)
:: Get beta version info
set "cmd=!cmd_to_get_version:[version_domain]=%domain_beta_version%!"
:: Get tokens after the first 4 lines of the output
for /f "skip=4 tokens=2,3,4 delims=.;" %%a in ('"!cmd!"') do if not defined bv_beta_number (
	set "bv_major=%%a"
	set "bv_minor=%%b"
	set "bv_beta_number=%%c"
)
:: Test if it is a beta or release candidate, or if no beta is available
if defined bv_beta_number (
	if !bv_beta_number! GEQ 229 (
		set /a "bv_beta_number -= 228"
		set "bv_beta_number=!code_rc!!bv_beta_number!"
	) else if !bv_beta_number! GEQ 129 (
		set /a "bv_beta_number -= 128"
		set "bv_beta_number=!code_beta!!bv_beta_number!"
	) else (
		:: If there is no beta number, beta testing has finished
		set "bv_beta_number="
		:: Beta testing ended, but perhaps info about final wasn't updated yet, update if necessary
		if defined v_major (
			set "flag_update_version="
			if !bv_major! GTR !v_major! set "flag_update_version=1"
			if !bv_major! EQU !v_major! if !bv_minor! GTR !v_minor! set "flag_update_version=1"
			if defined flag_update_version (
				set "v_major=!bv_major!"
				set "v_minor=!bv_minor!"
				set "v_patch_letter="
			)
		)
	)
)
:: Make sure minor version is 2 digits
if defined v_minor if "!v_minor:~1,1!"=="" set "v_minor=0!v_minor!"
if defined bv_minor if "!bv_minor:~1,1!"=="" set "bv_minor=0!bv_minor!"
:end_retrieving_version_info

:: Show header
if defined msg_header echo !msg_header!
echo:

:: Show version information
set "v_version=!txt_unknown_version!"
if defined v_major set "v_version=!v_major!.!v_minor!!v_patch_letter!"
set "bv_version=!txt_unknown_version!"
if defined bv_major (
	set "bv_version=!txt_beta_not_available!"
	if defined bv_beta_number (
		set "bv_version=!bv_major!.!bv_minor!!bv_beta_number!"
		set "bv_version=!bv_version:%code_beta%=%txt_beta%!"
		set "bv_version=!bv_version:%code_rc%=%txt_rc%!"
	)
)
if defined flag_specified_version (
	if defined v_major (
		set "msg=!msg_flag_specified_version:[version]=%v_version%!"
	) else (
		set "msg=!msg_flag_specified_version:[version]=%bv_version%!"
	)
	echo !msg!
) else (
	set "msg=!msg_latest_version:[version]=%v_version%!"
	echo !msg!
	set "msg=!msg_latest_bversion:[version]=%bv_version%!"
	echo !msg!
)
echo:

:: Pre-process download list
set "flag_final_skipped="
set "flag_beta_skipped="
set "new_list= "
:: Process download list
for %%i in (!download_list!) do (
	set "download_item=%%~i"
	if not "!all_finals!"=="!all_finals: %%~i =!" (
		:: Final version download
		if not defined v_major (
			if defined flag_specified_version (
				:: Convert any final download to beta download if a beta version was specified
				set "download_item=b!download_item!"
			) else (
				:: Skip download if it cannot be downloaded
				set "download_item="
				set "flag_final_skipped=1"
			)
		)
	) else if not "!all_betas!"=="!all_betas: %%~i =!" (
		:: Beta version download
		if not defined bv_beta_number (
			if defined flag_specified_version (
				:: Convert any beta download to final download if a final version was specified
				set "download_item=!download_item:~1!"
			) else (
				:: Skip download if it cannot be downloaded
				set "download_item="
				set "flag_beta_skipped=1"
			)
		)
	)
	:: Filter out duplicate items on the download list
	for %%j in ("!download_item!") do if "!new_list!"=="!new_list: %%~j =!" set "new_list=!new_list! !download_item! "
)
set "download_list=!new_list!"

:: Show error or message if downloads were skipped
if not defined flag_specified_version (
	if defined flag_final_skipped echo !error_final_unknown!
	if defined flag_beta_skipped if not defined bv_major (
		echo !error_beta_unknown!
	) else (
		set "exit_code=1"
		echo !msg_beta_not_available!
	)
)

:: Fill in url masks as far as we can
set "mask_url_final=!mask_url_final:[v_major]=%v_major%!"
set "mask_url_final=!mask_url_final:[v_minor]=%v_minor%!"
set "mask_url_final=!mask_url_final:[v_patch]=%v_patch_letter%!"
set "mask_url_beta=!mask_url_beta:[v_major]=%bv_major%!"
set "mask_url_beta=!mask_url_beta:[v_minor]=%bv_minor%!"
set "mask_url_beta=!mask_url_beta:[v_bnumber]=%bv_beta_number%!"

:: Loop through download list and download each version
for %%i in (!download_list!) do (
	if not "!all_finals!"=="!all_finals: %%~i =!" (
		:: Final version download
		set "url=!mask_url_final:[bitness]=%%~i!"
		call :download_file url
	) else if not "!all_betas!"=="!all_betas: %%~i =!" (
		:: Beta version download, remove "b" to get bitness
		set "download_item=%%~i"
		for %%j in ("!download_item:b=!") do set "url=!mask_url_beta:[bitness]=%%~j!"
		call :download_file url
	)
)

:: Restore current folder if it was changed
if defined download_folder popd

:end_script
if defined flag_end_pause %cmd_end_pause%
exit /b !exit_code!

::
:: check_ipv4: Check if address is valid IPv4 address
::
:: Parameters:
::   %1: (Quoted) string containing 4 numbers separated by a dot. ("nnn.nnn.nnn.nnn")
::
:: Return value:
::   0: Address is valid
::   1: Address is invalid
::
:check_ipv4
setlocal EnableDelayedExpansion
set "address=%~1"
if not defined address exit /b 1
:: Remove leading zeros to prevent interpretation as octal numbers, code: (1%%a+1%%a-2%%a)
:: Divide by 256 to check if numbers are less than 256
:: If numbers are too big and assignment fails, invalid_ipv4 remains undefined
set "invalid_ipv4="
for /f "tokens=1-4 delims=." %%a in ("%address%") do (
	set /a "invalid_ipv4=(1%%a+1%%a-2%%a)/256 + (1%%b+1%%b-2%%b)/256 + (1%%c+1%%c-2%%c)/256 + (1%%d+1%%d-2%%d)/256" 2>nul
)
if not defined invalid_ipv4 exit /b 1
if !invalid_ipv4! NEQ 0 exit /b 1
exit /b 0

::
:: parse_version: Validate and parse version string, setting version variables
::
:: Parameters:
::   %1: Version string to validate and parse (already matched with ^[0-9][0-9]*\.[0-9][0-9][0-9a-z]*)
::   %2: Variable name for major version (final release)
::   %3: Variable name for minor version (final release)
::   %4: Variable name for patch letter (final release, e.g., "a")
::   %5: Variable name for major version (beta/RC)
::   %6: Variable name for minor version (beta/RC)
::   %7: Variable name for beta/RC number (e.g., "b1", "rc99")
::
:: Return value:
::   0: Version string is valid, variables set
::   1: Version string is invalid
::
:: Global variables:
::   code_beta
::   code_rc
::
:parse_version
setlocal EnableDelayedExpansion
set "version=%~1"
if not defined version exit /b 1
:: Check if dot is at position 2 or 3 (major version is 1 or 2 digits)
set "idx="
if "!version:~1,1!"=="." set "idx=1"
if "!version:~2,1!"=="." set "idx=2"
if not defined idx exit /b 1
:: Extract major version (before the dot) and minor version after dot (2 digits)
set "major=!version:~0,%idx%!"
set /a "idx+=1"
set "minor=!version:~%idx%,2!"
set /a "idx+=2"
set "rest=!version:~%idx%!"
if not defined rest (
	:: Final version without patch letter (e.g., 10.00)
	endlocal & set "%2=%major%" & set "%3=%minor%" & set "%4="
	exit /b 0
)
if "!rest:~0,1!" GEQ "a" if "!rest:~0,1!" LEQ "z" if "!rest:~1,1!"=="" (
	:: Final version with patch letter (e.g., 10.00a)
	endlocal & set "%2=%major%" & set "%3=%minor%" & set "%4=%rest%"
	exit /b 0
)
:: Extract "b" or "rc"
set "b_type="
:: The variables code_beta and code_rc are used so minimal changes are needed if the filename scheme for the installers are changed
if "!rest:~0,1!"=="b" set "b_type=!code_beta!" & set "rest=!rest:~1!"
if "!rest:~0,2!"=="rc" set "b_type=!code_rc!" & set "rest=!rest:~2!"
if not defined b_type exit /b 1
if not defined rest exit /b 1
:: Extract beta/RC number (1 or 2 digits)
set "b_num="
if "!rest:~0,1!" GEQ "0" if "!rest:~0,1!" LEQ "9" if "!rest:~1,1!"=="" (
	set "b_num=!rest!"
) else (
	if "!rest:~1,1!" GEQ "0" if "!rest:~1,1!" LEQ "9" if "!rest:~2,1!"=="" set "b_num=!rest!"
)
if not defined b_num exit /b 1
:: Valid beta/RC version (e.g., 10.00b1, 10.00rc12)
endlocal & set "%5=%major%" & set "%6=%minor%" & set "%7=%b_type%%b_num%"
exit /b 0

::
:: download_file: Download file from URL
::
:: Parameters:
::   %1: Variable name holding the URL to download
::
:: Global variables (apart from constants):
::   flag_force_download: Force downloading if file already exists locally
::   flag_delete_duplicates: Delete duplicates after downloading
::
:download_file
setlocal EnableDelayedExpansion
set "url=!%~1!"
if not defined url exit /b 1
:: Get filename from url
set "filename=!url!"
:remove_folder_from_filename
set "filename=!filename:*/=!"
if not defined filename (
	exit /b 1
) else (
	if not "!filename!"=="!filename:*/=!" goto :remove_folder_from_filename
)
:: Determine local filename
set "local_filename=!filename!"
set "flag_skip_download="
if exist "!local_filename!" (
	if defined flag_force_download (
		call :get_available_filename local_filename
		echo !msg_downloading_to1!"!url!"!msg_downloading_to2!"!local_filename!"
	) else (
		echo !msg_download_file_exists1!"!url!"!msg_download_file_exists2!
		set "flag_skip_download=1"
	)
) else (
	echo !msg_downloading!"!url!"
)
:: Start downloading
set "flag_download_failed="
if not defined flag_skip_download (
	"!download_program!" !download_params! "!local_filename!" "!url!"
	if !errorlevel! NEQ 0 (
		:: Download failed, clean up
		if exist "!local_filename!" del "!local_filename!"
		set "flag_download_failed=1"
	)
)
:: Delete duplicate files, regardless whether download failed or was skipped
if defined flag_delete_duplicates call :delete_duplicates "!filename!"
:: Exitcode 1 if download failed
if defined flag_download_failed exit /b 1
exit /b 0

::
:: get_available_filename: Get a filename that is not in use
::
:: Parameters:
::   %1: Name of variable holding the filename
::
:get_available_filename
setlocal EnableDelayedExpansion
set "filename=!%~1!"
if not defined filename exit /b 1
if not exist "!filename!" exit /b 0
for %%f in ("!filename!") do (
	set "basename=%%~nf"
	set "ext=%%~xf"
)
set /a "seq=0"
:next_sequence_number
set /a "seq+=1"
set "filename=!basename! (!seq!)!ext!"
if exist "!filename!" goto :next_sequence_number
endlocal & set "%~1=%filename%"
exit /b 0

::
:: delete_duplicates: Delete duplicate "filename (n).exe" files
::
:: Parameters:
::   %1: Filename without sequence number
::
:delete_duplicates
setlocal EnableDelayedExpansion
set "basename=%~n1"
set "ext=%~x1"
if not defined basename exit /b
:: Clear variables with name that starts with "kept_file_"
for /f "delims==" %%v in ('set "kept_file_" 2^>nul') do set "%%v="
:: Create dir list
set "dir_list=!basename!!ext!"
for /l %%i in (0,1,99) do (
	set dir_list=!dir_list! "!basename! (%%i)!ext!"
)
:: Check if there are more than 1 existing files we would check
set /a "file_count=0"
for /f "eol= delims=" %%f in ('dir /b /a-d-r-s-h %dir_list% 2^>nul') do (
	set /a "file_count+=1"
	if !file_count! EQU 2 goto :second_file_found
)
exit /b
:second_file_found
set /a "idx_end_char=dupchk_hash_length-1"
set /a "idx_next_char=dupchk_hash_length+0"
:: Loop through existing files, skipping read-only/hidden/system files
for /f "eol= delims=" %%f in ('dir /b /a-d-r-s-h %dir_list% 2^>nul') do (
	set "fsize=%%~zf"
	:: Create hash
	set "hash="
	set "token="
	:: Get first token from second line of output
	for /f "skip=1" %%h in ('!cmd_create_hash! "%%f" !dupchk_hash_algo!') do (
		if not errorlevel 1 if not defined token set "token=%%h"
	)
	if defined token (
		:: Check if token consists of hex digits
		set token|findstr /irc:"^token=[0-9A-F]*$" >nul
		:: Check if token length is hash length, before assuming it is the hash
		if not errorlevel 1 if not "!token:~%idx_end_char%,1!"=="" if "!token:~%idx_next_char%,1!"=="" set "hash=!token!"
	)
	:: If hash is known, delete file if it is a duplicate file
	if defined hash (
		set "key=!fsize!_!hash!"
		if defined kept_file_!key! (
			echo !msg_deleting_duplicate!"%%f"
			del "%%f"
		) else (
			set "kept_file_!key!=1"
		)
	)
)
exit /b


Rem
Rem  History:
Rem
Rem  2025-06-30 Release v1.2b
Rem  2025-06-30 Support full path to download program with fallback to PATH and script folder
Rem  2025-06-30 Support curl folder containing ^ and ! characters
Rem
Rem  2025-06-29 Release v1.1b
Rem  2025-06-29 Search for curl within the script folder if it cannot be found
Rem  2025-06-29 Improved comments and help text
Rem
Rem  2025-06-28 Release v1.0b (first release)
Rem
User avatar
petermad
Power Member
Power Member
Posts: 16157
Joined: 2003-02-05, 20:24 UTC
Location: Denmark
Contact:

Re: tcdownload.cmd v1.0b - Downloads latest version of Total Commander

Post by *petermad »

Nice tool.

If I enter:

Code: Select all

tcdownload /b64 /v:11.51
I expect to get the last 11.51 beta version, but I get the final 11.51 version

If I on the other hand enter:

Code: Select all

tcdownload /b64 /v:11.51rc5
then it works as expected - but then I have to know that rc5 was the last 11.51 beta version.
License #524 (1994)
Danish Total Commander Translator
TC 11.55rc4 32+64bit on Win XP 32bit & Win 7, 8.1 & 10 (22H2) 64bit, 'Everything' 1.5.0.1393a
TC 3.60b4 on Android 6, 13, 14
TC Extended Menus | TC Languagebar | TC Dark Help | PHSM-Calendar
User avatar
white
Power Member
Power Member
Posts: 6022
Joined: 2003-11-19, 08:16 UTC
Location: Netherlands

Re: tcdownload.cmd v1.0b - Downloads latest version of Total Commander

Post by *white »

petermad wrote: 2025-06-28, 23:04 UTC If I enter:

Code: Select all

tcdownload /b64 /v:11.51
I expect to get the last 11.51 beta version, but I get the final 11.51 version
Correct, this is by design. The tool is meant to download the latest final or beta version. As a bonus you can specify a precise final or beta version to download. In that case you already specified whether it is a final or beta and it makes no difference whether you use /b64 or /64.
petermad wrote: 2025-06-28, 23:04 UTC If I on the other hand enter:

Code: Select all

tcdownload /b64 /v:11.51rc5
then it works as expected - but then I have to know that rc5 was the last 11.51 beta version.
The tool checks the fake domains releaseversion.ghisler.com and releasebeta.ghisler.com to determine the latest version of Total Commander and if available the latest beta version. It cannot determine the latest beta version of a specified older version.
Bohny
Junior Member
Junior Member
Posts: 7
Joined: 2023-08-04, 00:24 UTC

Re: tcdownload.cmd v1.0b - Downloads latest version of Total Commander

Post by *Bohny »

Very convenient tool !
Please add an option to check the latest version of Total Commander
User avatar
petermad
Power Member
Power Member
Posts: 16157
Joined: 2003-02-05, 20:24 UTC
Location: Denmark
Contact:

Re: tcdownload.cmd v1.0b - Downloads latest version of Total Commander

Post by *petermad »

The tool is meant to download the latest final or beta version
So I guess, I'll have to wait until the next beta test starts to test the paramertrrs /B32, /B64, /b32_64 and /ALLB

It could argued that tc1155x*_rc7.exe are the latest beta versions. Maybe it should be rephrased to: "is meant to download the latest final or ongoing beta version"
License #524 (1994)
Danish Total Commander Translator
TC 11.55rc4 32+64bit on Win XP 32bit & Win 7, 8.1 & 10 (22H2) 64bit, 'Everything' 1.5.0.1393a
TC 3.60b4 on Android 6, 13, 14
TC Extended Menus | TC Languagebar | TC Dark Help | PHSM-Calendar
User avatar
petermad
Power Member
Power Member
Posts: 16157
Joined: 2003-02-05, 20:24 UTC
Location: Denmark
Contact:

Re: tcdownload.cmd v1.0b - Downloads latest version of Total Commander

Post by *petermad »

I have now tested it on Windows 7 with the curl.exe from this package: https://curl.se/windows/dl-8.14.1_2/curl-8.14.1_2-win32-mingw.zip <https://curl.se/windows/> - and it worked fine.
License #524 (1994)
Danish Total Commander Translator
TC 11.55rc4 32+64bit on Win XP 32bit & Win 7, 8.1 & 10 (22H2) 64bit, 'Everything' 1.5.0.1393a
TC 3.60b4 on Android 6, 13, 14
TC Extended Menus | TC Languagebar | TC Dark Help | PHSM-Calendar
User avatar
nsp
Power Member
Power Member
Posts: 1959
Joined: 2005-12-04, 08:39 UTC
Location: Lyon (FRANCE)
Contact:

Re: tcdownload.cmd v1.0b - Downloads latest version of Total Commander

Post by *nsp »

I'm using a guessing method to see program version available on a remote server. I use it to get latest everything alpha version, and some other opensource software..

I use a naming pattern and variable number/letters I have a stop/skip condition for the number/letter increments to skip missing files and stop at latest.

I gave a try for Total Commander Beta:
remote base url: "https://www.totalcommander.ch/beta/"
file prefix: "tc"+Mv+mv+arch+"_rc"
file postfix: ".exe"
pattern: #9 means a number without trailing zero

For tc1155 32_64 it gives:

Code: Select all

https://www.totalcommander.ch/beta/tc1155x32_64_rc1.exe
https://www.totalcommander.ch/beta/tc1155x32_64_rc2.exe
https://www.totalcommander.ch/beta/tc1155x32_64_rc3.exe
https://www.totalcommander.ch/beta/tc1155x32_64_rc4.exe
https://www.totalcommander.ch/beta/tc1155x32_64_rc5.exe
https://www.totalcommander.ch/beta/tc1155x32_64_rc6.exe
https://www.totalcommander.ch/beta/tc1155x32_64_rc7.exe
for tc 1151 x64 it gives:

Code: Select all

https://www.totalcommander.ch/beta/tc1151x64_rc1.exe
https://www.totalcommander.ch/beta/tc1151x64_rc2.exe
https://www.totalcommander.ch/beta/tc1151x64_rc3.exe
https://www.totalcommander.ch/beta/tc1151x64_rc4.exe
https://www.totalcommander.ch/beta/tc1151x64_rc5.exe
..
User avatar
nsp
Power Member
Power Member
Posts: 1959
Joined: 2005-12-04, 08:39 UTC
Location: Lyon (FRANCE)
Contact:

Re: tcdownload.cmd v1.0b - Downloads latest version of Total Commander

Post by *nsp »

@petermad you can also download from TC using the background file transfer add URL.
To get a bunch at once, you can also create a list file and use FTP download from list.
User avatar
petermad
Power Member
Power Member
Posts: 16157
Joined: 2003-02-05, 20:24 UTC
Location: Denmark
Contact:

Re: tcdownload.cmd v1.0b - Downloads latest version of Total Commander

Post by *petermad »

2white
Under Windows 7 I made a %COMMANDER_PATH%\Tools\TCDownload folder with curl.exe (from https://curl.se/windows/dl-8.14.1_2/curl-8.14.1_2-win32-mingw.zip ) and tcdownload.cmd - it worked fine for downloading to %COMMANDER_PATH%\Tools\TCDownload, but when I used the [drive:][path] option to download to c:\TCDownloads - then curl.exe could not be found.

I solved this by making this tcdownload2.cmd file:

Code: Select all

@echo off
set path=%path%;%~dp0
tcdownload.cmd c:\TCDownloads /P /ALL
May I suggest that you add: set path=%path%;%~dp0 to tcdownload.cmd - unless you see any pitfalls doing it
License #524 (1994)
Danish Total Commander Translator
TC 11.55rc4 32+64bit on Win XP 32bit & Win 7, 8.1 & 10 (22H2) 64bit, 'Everything' 1.5.0.1393a
TC 3.60b4 on Android 6, 13, 14
TC Extended Menus | TC Languagebar | TC Dark Help | PHSM-Calendar
User avatar
white
Power Member
Power Member
Posts: 6022
Joined: 2003-11-19, 08:16 UTC
Location: Netherlands

Re: tcdownload.cmd v1.0b - Downloads latest version of Total Commander

Post by *white »

Bohny wrote: 2025-06-29, 03:59 UTC Please add an option to check the latest version of Total Commander
You mean show latest version only, without downloading anything?
petermad wrote: 2025-06-29, 06:33 UTC
The tool is meant to download the latest final or beta version
So I guess, I'll have to wait until the next beta test starts to test the paramertrrs /B32, /B64, /b32_64 and /ALLB
For testing purposes you could temporarily add the line:

Code: Select all

set "bv_beta_number=235"
before the lines:

Code: Select all

:: Test if it is a beta or release candidate, or if no beta is available
if defined bv_beta_number (
Don't forget to remove it again though :)
(number 235 = release candidate 7)
petermad wrote: 2025-06-29, 06:33 UTC It could argued that tc1155x*_rc7.exe are the latest beta versions. Maybe it should be rephrased to: "is meant to download the latest final or ongoing beta version"
It shows the text "> No beta for a new release is available at this time.", which basically tells it already. But I added some text to the comments, the help text, and the extended help text.
petermad wrote: 2025-06-29, 08:21 UTC May I suggest that you add: set path=%path%;%~dp0 to tcdownload.cmd - unless you see any pitfalls doing it
Instead of adjusting the path, I added code to search for it anywhere within the script's folder. So it can be in a subfolder too.

I cleaned up the code too. There was a leftover and I mixed using tabs and spaces for indentation. New release:
white wrote: 2025-06-28, 19:28 UTC Rem 2025-06-29 Release v1.1b
Rem 2025-06-29 Search for curl within the script folder if it cannot be found
Rem 2025-06-29 Improved comments and help text
User avatar
petermad
Power Member
Power Member
Posts: 16157
Joined: 2003-02-05, 20:24 UTC
Location: Denmark
Contact:

Re: tcdownload.cmd v1.1b - Downloads latest version of Total Commander

Post by *petermad »

2white
Instead of adjusting the path, I added code to search for it anywhere within the script's folder.
Thanks it works fine.

I have now implemented it like this:

Code: Select all

@echo off
call tcdownload.cmd c:\TCDownloads\Finals /ALLF
echo.
call tcdownload.cmd c:\TCDownloads\Betas /ALLB
echo.
pause
This way I can keep finals and betas separated.
Using call is necessary because of of exit with the /b parameter in tcdownload.cmd.
License #524 (1994)
Danish Total Commander Translator
TC 11.55rc4 32+64bit on Win XP 32bit & Win 7, 8.1 & 10 (22H2) 64bit, 'Everything' 1.5.0.1393a
TC 3.60b4 on Android 6, 13, 14
TC Extended Menus | TC Languagebar | TC Dark Help | PHSM-Calendar
User avatar
white
Power Member
Power Member
Posts: 6022
Joined: 2003-11-19, 08:16 UTC
Location: Netherlands

Re: tcdownload.cmd v1.1b - Downloads latest version of Total Commander

Post by *white »

petermad wrote: 2025-06-29, 17:34 UTC
Instead of adjusting the path, I added code to search for it anywhere within the script's folder.
Thanks it works fine.
Not completely. It failed when the path contained ^ or ! characters. I think I fixed it though, and you can now also specify full path in this line:
set "download_program=curl.exe"
New release:
white wrote: 2025-06-28, 19:28 UTC Rem 2025-06-30 Release v1.2b
Rem 2025-06-30 Support full path to download program with fallback to PATH and script folder
Rem 2025-06-30 Support curl folder containing ^ and ! characters


petermad wrote: 2025-06-29, 17:34 UTC Using call is necessary because of of exit with the /b parameter in tcdownload.cmd.
? Call is always necessary when you launch a batch file from a batch file and want to return.
Bohny
Junior Member
Junior Member
Posts: 7
Joined: 2023-08-04, 00:24 UTC

Re: tcdownload.cmd v1.0b - Downloads latest version of Total Commander

Post by *Bohny »

white wrote: 2025-06-29, 14:08 UTC
Bohny wrote: 2025-06-29, 03:59 UTC Please add an option to check the latest version of Total Commander
You mean show latest version only, without downloading anything?
Add a parameter or switch
KozakMak
Power Member
Power Member
Posts: 510
Joined: 2021-05-24, 12:39 UTC
Location: UA

Re: tcdownload.cmd v1.2b - Downloads latest version of Total Commander

Post by *KozakMak »

Sounds good, doesn't work :lol:

Code: Select all

TCDOWNLOAD v1.2b

Latest final version : ns.cloudflareletters:~com,1
Latest beta version  : ns.cloudflare release candidate -228

Downloading "https://www.totalcommander.ch/nscloudflare/tcmdnscloudflareletters:~com,1x64.exe"
curl: (22) The requested URL returned error: 404
OS: Win10 | TC: latest x64
User avatar
petermad
Power Member
Power Member
Posts: 16157
Joined: 2003-02-05, 20:24 UTC
Location: Denmark
Contact:

Re: tcdownload.cmd v1.2b - Downloads latest version of Total Commander

Post by *petermad »

? Call is always necessary when you launch a batch file from a batch file
Of course, my bad.
License #524 (1994)
Danish Total Commander Translator
TC 11.55rc4 32+64bit on Win XP 32bit & Win 7, 8.1 & 10 (22H2) 64bit, 'Everything' 1.5.0.1393a
TC 3.60b4 on Android 6, 13, 14
TC Extended Menus | TC Languagebar | TC Dark Help | PHSM-Calendar
Post Reply