mirror of
https://github.com/dockur/windows.git
synced 2026-07-15 01:38:16 +01:00
feat: Improve download function (#1826)
This commit is contained in:
+184
-164
@@ -1,42 +1,42 @@
|
|||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
set -Eeuo pipefail
|
set -Eeuo pipefail
|
||||||
|
|
||||||
handle_curl_error() {
|
handleCurlError() {
|
||||||
|
|
||||||
local error_code="$1"
|
local code="$1"
|
||||||
local server_name="$2"
|
local server="$2"
|
||||||
|
|
||||||
case "$error_code" in
|
case "$code" in
|
||||||
1) error "Unsupported protocol!" ;;
|
1) error "Unsupported protocol!" ;;
|
||||||
2) error "Failed to initialize curl!" ;;
|
2) error "Failed to initialize curl!" ;;
|
||||||
3) error "The URL format is malformed!" ;;
|
3) error "The URL format is malformed!" ;;
|
||||||
5) error "Failed to resolve address of proxy host!" ;;
|
5) error "Failed to resolve address of proxy host!" ;;
|
||||||
6) error "Failed to resolve $server_name servers! Is there an Internet connection?" ;;
|
6) error "Failed to resolve $server servers! Is there an Internet connection?" ;;
|
||||||
7) error "Failed to contact $server_name servers! Is there an Internet connection or is the server down?" ;;
|
7) error "Failed to contact $server servers! Is there an Internet connection or is the server down?" ;;
|
||||||
8) error "$server_name servers returned a malformed HTTP response!" ;;
|
8) error "$server servers returned a malformed HTTP response!" ;;
|
||||||
16) error "A problem was detected in the HTTP2 framing layer!" ;;
|
16) error "A problem was detected in the HTTP2 framing layer!" ;;
|
||||||
22) error "$server_name servers returned a failing HTTP status code!" ;;
|
22) error "$server servers returned a failing HTTP status code!" ;;
|
||||||
23) error "Failed at writing Windows media to disk! Out of disk space or permission error?" ;;
|
23) error "Failed at writing Windows media to disk! Out of disk space or permission error?" ;;
|
||||||
26) error "Failed to read Windows media from disk!" ;;
|
26) error "Failed to read Windows media from disk!" ;;
|
||||||
27) error "Ran out of memory during download!" ;;
|
27) error "Ran out of memory during download!" ;;
|
||||||
28) error "Connection timed out to $server_name server!" ;;
|
28) error "Connection timed out to $server server!" ;;
|
||||||
35) error "SSL connection error from $server_name server!" ;;
|
35) error "SSL connection error from $server server!" ;;
|
||||||
36) error "Failed to continue earlier download!" ;;
|
36) error "Failed to continue earlier download!" ;;
|
||||||
52) error "Received no data from the $server_name server!" ;;
|
52) error "Received no data from the $server server!" ;;
|
||||||
63) error "$server_name servers returned an unexpectedly large response!" ;;
|
63) error "$server servers returned an unexpectedly large response!" ;;
|
||||||
126) error "Curl command cannot be executed!" ;;
|
126) error "Curl command cannot be executed!" ;;
|
||||||
127) error "Curl command not found!" ;;
|
127) error "Curl command not found!" ;;
|
||||||
*)
|
*)
|
||||||
if (( error_code <= 125 )); then
|
if (( code <= 125 )); then
|
||||||
# Must be some other server or network error (possibly with this specific request/file)
|
# Must be some other server or network error (possibly with this specific request/file)
|
||||||
# This is when accounting for all possible errors in the curl manual assuming a correctly formed
|
# This is when accounting for all possible errors in the curl manual assuming a correctly formed
|
||||||
# curl command and an HTTP(S) request, using only the curl features we're using, and a sane build.
|
# curl command and an HTTP(S) request, using only the curl features we're using, and a sane build.
|
||||||
error "Miscellaneous server or network error, reason: $error_code"
|
error "Miscellaneous server or network error, reason: $code"
|
||||||
else
|
else
|
||||||
case "$(kill -l "$error_code" 2>/dev/null || true)" in
|
case "$(kill -l "$code" 2>/dev/null || true)" in
|
||||||
INT) error "Curl was interrupted!" ;;
|
INT) error "Curl was interrupted!" ;;
|
||||||
SEGV | ABRT) error "Curl crashed! Please report any core dumps to curl developers." ;;
|
SEGV | ABRT) error "Curl crashed! Please report any core dumps to curl developers." ;;
|
||||||
*) error "Curl terminated due to fatal signal $error_code !" ;;
|
*) error "Curl terminated due to fatal signal $code !" ;;
|
||||||
esac
|
esac
|
||||||
fi
|
fi
|
||||||
;;
|
;;
|
||||||
@@ -45,7 +45,7 @@ handle_curl_error() {
|
|||||||
return 1
|
return 1
|
||||||
}
|
}
|
||||||
|
|
||||||
get_agent() {
|
getAgent() {
|
||||||
|
|
||||||
local browser_version
|
local browser_version
|
||||||
|
|
||||||
@@ -56,41 +56,42 @@ get_agent() {
|
|||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
download_windows() {
|
downloadWindows() {
|
||||||
|
|
||||||
local id="$1"
|
local id="$1"
|
||||||
local lang="$2"
|
local lang="$2"
|
||||||
local desc="$3"
|
local desc="$3"
|
||||||
|
|
||||||
local rc=0
|
local rc=0
|
||||||
local ovw="" rticks="" mdt="" sku_id="" sku_url=""
|
local ovToken="" ovTicks="" ovTime=""
|
||||||
local iso_url="" iso_json="" language="" org_id=""
|
local skuId="" skuUrl="" skuJson=""
|
||||||
local instance_id="" vls_url="" ov_url="" ov_data=""
|
local linkUrl="" linkJson="" link=""
|
||||||
local session_id="" user_agent="" download_type=""
|
local language="" orgId=""
|
||||||
local windows_version="" iso_download_link=""
|
local instance="" vlsUrl="" ovUrl="" ovData=""
|
||||||
local download_page_html="" product_edition_id=""
|
local session="" agent="" type=""
|
||||||
local language_skuid_json=""
|
local winVer="" page="" productId=""
|
||||||
local profile="606624d44113"
|
local profile="606624d44113"
|
||||||
|
|
||||||
user_agent=$(get_agent)
|
agent=$(getAgent)
|
||||||
language=$(getLanguage "$lang" "name")
|
language=$(getLanguage "$lang" "name")
|
||||||
|
|
||||||
case "${id,,}" in
|
case "${id,,}" in
|
||||||
"win11x64" ) windows_version="11" && download_type="1" ;;
|
"win11x64" ) winVer="11" && type="1" ;;
|
||||||
"win11arm64" ) windows_version="11arm64" && download_type="2" ;;
|
"win11arm64" ) winVer="11arm64" && type="2" ;;
|
||||||
* ) error "Invalid VERSION specified, value \"$id\" is not recognized!" && return 1 ;;
|
* ) error "Invalid VERSION specified, value \"$id\" is not recognized!" && return 1 ;;
|
||||||
esac
|
esac
|
||||||
|
|
||||||
local url="https://www.microsoft.com/en-us/software-download/windows$windows_version"
|
local url="https://www.microsoft.com/en-us/software-download/windows$winVer"
|
||||||
|
|
||||||
# uuidgen: For MacOS (installed by default) and other systems (e.g. with no /proc) that don't have a kernel interface for generating random UUIDs
|
# uuidgen: For MacOS (installed by default) and other systems (e.g. with no /proc) that don't have a kernel interface for generating random UUIDs
|
||||||
if ! session_id=$(cat /proc/sys/kernel/random/uuid 2> /dev/null || uuidgen --random); then
|
if ! session=$(cat /proc/sys/kernel/random/uuid 2> /dev/null || uuidgen --random); then
|
||||||
error "Failed to generate session ID!"
|
error "Failed to generate session ID!"
|
||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
session_id="${session_id//[![:print:]]/}"
|
session="${session//[![:print:]]/}"
|
||||||
|
|
||||||
if [ -z "$session_id" ]; then
|
if [ -z "$session" ]; then
|
||||||
error "Failed to generate session ID!"
|
error "Failed to generate session ID!"
|
||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
@@ -101,189 +102,189 @@ download_windows() {
|
|||||||
# Also, keeping a "$WindowsVersions" array like Fido does would be way too much of a maintenance burden
|
# Also, keeping a "$WindowsVersions" array like Fido does would be way too much of a maintenance burden
|
||||||
# Remove "Accept" header that curl sends by default
|
# Remove "Accept" header that curl sends by default
|
||||||
enabled "$DEBUG" && echo "Parsing download page: ${url}"
|
enabled "$DEBUG" && echo "Parsing download page: ${url}"
|
||||||
download_page_html=$(curl --silent --max-time 30 --user-agent "$user_agent" --header "Accept:" --max-filesize 1M --fail --proto =https --tlsv1.2 --http1.1 -- "$url") || {
|
page=$(curl --silent --max-time 30 --user-agent "$agent" --header "Accept:" --max-filesize 1M --fail --proto =https --tlsv1.2 --http1.1 -- "$url") || {
|
||||||
handle_curl_error "$?" "Microsoft"
|
handleCurlError "$?" "Microsoft"
|
||||||
return $?
|
return $?
|
||||||
}
|
}
|
||||||
|
|
||||||
enabled "$DEBUG" && echo -n "Getting Product edition ID: "
|
enabled "$DEBUG" && echo -n "Getting Product edition ID: "
|
||||||
product_edition_id=$(echo "$download_page_html" | grep -Eo '<option value="[0-9]+">Windows' | cut -d '"' -f 2 | head -n 1 | tr -cd '0-9' | head -c 16)
|
productId=$(echo "$page" | grep -Eo '<option value="[0-9]+">Windows' | cut -d '"' -f 2 | head -n 1 | tr -cd '0-9' | head -c 16)
|
||||||
enabled "$DEBUG" && echo "$product_edition_id"
|
enabled "$DEBUG" && echo "$productId"
|
||||||
|
|
||||||
if [ -z "$product_edition_id" ]; then
|
if [ -z "$productId" ]; then
|
||||||
error "Product edition ID not found!"
|
error "Product edition ID not found!"
|
||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Microsoft download "protection" requires the sessionId to be whitelisted through vlscppe.microsoft.com/tags
|
# Microsoft download "protection" requires the sessionId to be whitelisted through vlscppe.microsoft.com/tags
|
||||||
|
|
||||||
org_id="y6jn8c31"
|
orgId="y6jn8c31"
|
||||||
vls_url="https://vlscppe.microsoft.com/tags?org_id=$org_id&session_id=$session_id"
|
vlsUrl="https://vlscppe.microsoft.com/tags?org_id=$orgId&session_id=$session"
|
||||||
|
|
||||||
enabled "$DEBUG" && echo "Getting Session ID: $session_id"
|
enabled "$DEBUG" && echo "Getting Session ID: $session"
|
||||||
|
|
||||||
# Permit Session ID
|
# Permit Session ID
|
||||||
curl --silent --max-time 30 --output /dev/null --user-agent "$user_agent" --header "Accept:" --max-filesize 100K --fail --proto =https --tlsv1.2 --http1.1 -- "$vls_url" || {
|
curl --silent --max-time 30 --output /dev/null --user-agent "$agent" --header "Accept:" --max-filesize 100K --fail --proto =https --tlsv1.2 --http1.1 -- "$vlsUrl" || {
|
||||||
# This should only happen if there's been some change to how this API works
|
# This should only happen if there's been some change to how this API works
|
||||||
handle_curl_error "$?" "Microsoft"
|
handleCurlError "$?" "Microsoft"
|
||||||
return $?
|
return $?
|
||||||
}
|
}
|
||||||
|
|
||||||
# Microsoft download "protection" also requires an ov-df.microsoft.com request/reply
|
# Microsoft download "protection" also requires an ov-df.microsoft.com request/reply
|
||||||
# 1) Request mdt.js to get w and rticks. InstanceId is (currently) constant.
|
# 1) Request mdt.js to get w and rticks. InstanceId is (currently) constant.
|
||||||
|
|
||||||
instance_id="560dc9f3-1aa5-4a2f-b63c-9e18f8d0e175"
|
instance="560dc9f3-1aa5-4a2f-b63c-9e18f8d0e175"
|
||||||
ov_url="https://ov-df.microsoft.com/mdt.js?instanceId=$instance_id&PageId=si&session_id=$session_id"
|
ovUrl="https://ov-df.microsoft.com/mdt.js?instanceId=$instance&PageId=si&session_id=$session"
|
||||||
|
|
||||||
enabled "$DEBUG" && echo -n "Getting OV data: "
|
enabled "$DEBUG" && echo -n "Getting OV data: "
|
||||||
|
|
||||||
ov_data=$(curl --silent --max-time 30 --user-agent "$user_agent" --header "Accept:" --max-filesize 1M --fail --proto =https --tlsv1.2 --http1.1 -- "$ov_url") || {
|
ovData=$(curl --silent --max-time 30 --user-agent "$agent" --header "Accept:" --max-filesize 1M --fail --proto =https --tlsv1.2 --http1.1 -- "$ovUrl") || {
|
||||||
handle_curl_error "$?" "Microsoft"
|
handleCurlError "$?" "Microsoft"
|
||||||
return $?
|
return $?
|
||||||
}
|
}
|
||||||
|
|
||||||
if [[ $ov_data =~ [\?\&]w=([A-Fa-f0-9]+) ]]; then
|
if [[ $ovData =~ [\?\&]w=([A-Fa-f0-9]+) ]]; then
|
||||||
ovw="${BASH_REMATCH[1]}"
|
ovToken="${BASH_REMATCH[1]}"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [[ $ov_data =~ rticks=\"\+?([0-9]+) ]]; then
|
if [[ $ovData =~ rticks=\"\+?([0-9]+) ]]; then
|
||||||
rticks="${BASH_REMATCH[1]}"
|
ovTicks="${BASH_REMATCH[1]}"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [[ -z $ovw || -z $rticks ]]; then
|
if [[ -z $ovToken || -z $ovTicks ]]; then
|
||||||
error "Could not extract ov-df data from Microsoft server!"
|
error "Could not extract ov-df data from Microsoft server!"
|
||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
enabled "$DEBUG" && echo "$ovw"
|
enabled "$DEBUG" && echo "$ovToken"
|
||||||
|
|
||||||
sleep 0.2
|
sleep 0.2
|
||||||
|
|
||||||
# 2) Send a reply with session ID, current epoch and previously retrieved w and rticks
|
# 2) Send a reply with session ID, current epoch and previously retrieved w and rticks
|
||||||
|
|
||||||
mdt=$(date +%s%3N)
|
ovTime=$(date +%s%3N)
|
||||||
ov_url="https://ov-df.microsoft.com/?session_id=$session_id&CustomerId=$instance_id&PageId=si&w=$ovw&mdt=$mdt&rticks=$rticks"
|
ovUrl="https://ov-df.microsoft.com/?session_id=$session&CustomerId=$instance&PageId=si&w=$ovToken&mdt=$ovTime&rticks=$ovTicks"
|
||||||
|
|
||||||
enabled "$DEBUG" && echo "Sending OV reply: $instance_id"
|
enabled "$DEBUG" && echo "Sending OV reply: $instance"
|
||||||
|
|
||||||
curl --silent --max-time 30 --output /dev/null --user-agent "$user_agent" --header "Accept:" --max-filesize 100K --fail --proto =https --tlsv1.2 --http1.1 -- "$ov_url" || {
|
curl --silent --max-time 30 --output /dev/null --user-agent "$agent" --header "Accept:" --max-filesize 100K --fail --proto =https --tlsv1.2 --http1.1 -- "$ovUrl" || {
|
||||||
# This should only happen if there's been some change to how this API works
|
# This should only happen if there's been some change to how this API works
|
||||||
handle_curl_error "$?" "Microsoft"
|
handleCurlError "$?" "Microsoft"
|
||||||
return $?
|
return $?
|
||||||
}
|
}
|
||||||
|
|
||||||
enabled "$DEBUG" && echo -n "Getting language SKU ID: "
|
enabled "$DEBUG" && echo -n "Getting language SKU ID: "
|
||||||
|
|
||||||
sku_url="https://www.microsoft.com/software-download-connector/api/getskuinformationbyproductedition?profile=$profile&ProductEditionId=$product_edition_id&SKU=undefined&friendlyFileName=undefined&Locale=en-US&sessionID=$session_id"
|
skuUrl="https://www.microsoft.com/software-download-connector/api/getskuinformationbyproductedition?profile=$profile&ProductEditionId=$productId&SKU=undefined&friendlyFileName=undefined&Locale=en-US&sessionID=$session"
|
||||||
language_skuid_json=$(curl --silent --max-time 30 --request GET --user-agent "$user_agent" --referer "$url" --header "Accept:" --max-filesize 100K --fail --proto =https --tlsv1.2 --http1.1 -- "$sku_url") || {
|
skuJson=$(curl --silent --max-time 30 --request GET --user-agent "$agent" --referer "$url" --header "Accept:" --max-filesize 100K --fail --proto =https --tlsv1.2 --http1.1 -- "$skuUrl") || {
|
||||||
handle_curl_error "$?" "Microsoft"
|
handleCurlError "$?" "Microsoft"
|
||||||
return $?
|
return $?
|
||||||
}
|
}
|
||||||
|
|
||||||
{ sku_id=$(echo "$language_skuid_json" | jq --arg LANG "$language" -r '.Skus[] | select(.Language==$LANG).Id') 2>/dev/null; rc=$?; } || :
|
{ skuId=$(echo "$skuJson" | jq --arg LANG "$language" -r '.Skus[] | select(.Language==$LANG).Id') 2>/dev/null; rc=$?; } || :
|
||||||
|
|
||||||
if [ -z "$sku_id" ] || [[ "${sku_id,,}" == "null" ]] || (( rc != 0 )); then
|
if [ -z "$skuId" ] || [[ "${skuId,,}" == "null" ]] || (( rc != 0 )); then
|
||||||
language=$(getLanguage "$lang" "desc")
|
language=$(getLanguage "$lang" "desc")
|
||||||
error "No download in the $language language available for $desc!"
|
error "No download in the $language language available for $desc!"
|
||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
enabled "$DEBUG" && echo "$sku_id"
|
enabled "$DEBUG" && echo "$skuId"
|
||||||
enabled "$DEBUG" && echo "Getting ISO download link..."
|
enabled "$DEBUG" && echo "Getting ISO download link..."
|
||||||
|
|
||||||
# Get ISO download link
|
# Get ISO download link
|
||||||
# If any request is going to be blocked by Microsoft it's always this last one (the previous requests always seem to succeed)
|
# If any request is going to be blocked by Microsoft it's always this last one (the previous requests always seem to succeed)
|
||||||
|
|
||||||
iso_url="https://www.microsoft.com/software-download-connector/api/GetProductDownloadLinksBySku?profile=$profile&ProductEditionId=undefined&SKU=$sku_id&friendlyFileName=undefined&Locale=en-US&sessionID=$session_id"
|
linkUrl="https://www.microsoft.com/software-download-connector/api/GetProductDownloadLinksBySku?profile=$profile&ProductEditionId=undefined&SKU=$skuId&friendlyFileName=undefined&Locale=en-US&sessionID=$session"
|
||||||
iso_json=$(curl --silent --max-time 30 --request GET --user-agent "$user_agent" --referer "$url" --header "Accept:" --max-filesize 100K --fail --proto =https --tlsv1.2 --http1.1 -- "$iso_url") || {
|
linkJson=$(curl --silent --max-time 30 --request GET --user-agent "$agent" --referer "$url" --header "Accept:" --max-filesize 100K --fail --proto =https --tlsv1.2 --http1.1 -- "$linkUrl") || {
|
||||||
handle_curl_error "$?" "Microsoft"
|
handleCurlError "$?" "Microsoft"
|
||||||
return $?
|
return $?
|
||||||
}
|
}
|
||||||
|
|
||||||
if ! [ "$iso_json" ]; then
|
if ! [ "$linkJson" ]; then
|
||||||
# This should only happen if there's been some change to how this API works
|
# This should only happen if there's been some change to how this API works
|
||||||
error "Microsoft servers gave us an empty response to our request for an automated download."
|
error "Microsoft servers gave us an empty response to our request for an automated download."
|
||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if echo "$iso_json" | grep -q "Sentinel marked this request as rejected."; then
|
if echo "$linkJson" | grep -q "Sentinel marked this request as rejected."; then
|
||||||
error "Microsoft blocked the automated download request based on your IP address."
|
error "Microsoft blocked the automated download request based on your IP address."
|
||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if echo "$iso_json" | grep -q "We are unable to complete your request at this time."; then
|
if echo "$linkJson" | grep -q "We are unable to complete your request at this time."; then
|
||||||
error "Microsoft blocked the automated download request based on your IP address."
|
error "Microsoft blocked the automated download request based on your IP address."
|
||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
{ iso_download_link=$(echo "$iso_json" | jq --argjson TYPE "$download_type" -r '.ProductDownloadOptions[] | select(.DownloadType==$TYPE).Uri') 2>/dev/null; rc=$?; } || :
|
{ link=$(echo "$linkJson" | jq --argjson TYPE "$type" -r '.ProductDownloadOptions[] | select(.DownloadType==$TYPE).Uri') 2>/dev/null; rc=$?; } || :
|
||||||
|
|
||||||
if [ -z "$iso_download_link" ] || [[ "${iso_download_link,,}" == "null" ]] || (( rc != 0 )); then
|
if [ -z "$link" ] || [[ "${link,,}" == "null" ]] || (( rc != 0 )); then
|
||||||
error "Microsoft server gave us no download link to our request for an automated download!"
|
error "Microsoft server gave us no download link to our request for an automated download!"
|
||||||
info "Response: $iso_json"
|
info "Response: $linkJson"
|
||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
MIDO_URL="$iso_download_link"
|
MIDO_URL="$link"
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
download_windows_eval() {
|
downloadWindowsEval() {
|
||||||
|
|
||||||
local id="$1"
|
local id="$1"
|
||||||
local lang="$2"
|
local lang="$2"
|
||||||
local desc="$3"
|
local desc="$3"
|
||||||
local filter="" culture="" compare="" language=""
|
local filter="" culture="" compare="" language=""
|
||||||
local user_agent="" enterprise_type="" windows_version=""
|
local agent="" type="" winVer=""
|
||||||
|
|
||||||
case "${id,,}" in
|
case "${id,,}" in
|
||||||
"win11${PLATFORM,,}-enterprise-eval" )
|
"win11${PLATFORM,,}-enterprise-eval" )
|
||||||
enterprise_type="enterprise"
|
type="enterprise"
|
||||||
windows_version="windows-11-enterprise" ;;
|
winVer="windows-11-enterprise" ;;
|
||||||
"win11${PLATFORM,,}-enterprise-iot-eval" )
|
"win11${PLATFORM,,}-enterprise-iot-eval" )
|
||||||
enterprise_type="iot"
|
type="iot"
|
||||||
windows_version="windows-11-iot-enterprise-ltsc-eval" ;;
|
winVer="windows-11-iot-enterprise-ltsc-eval" ;;
|
||||||
"win11${PLATFORM,,}-enterprise-ltsc-eval" )
|
"win11${PLATFORM,,}-enterprise-ltsc-eval" )
|
||||||
enterprise_type="iot"
|
type="iot"
|
||||||
windows_version="windows-11-iot-enterprise-ltsc-eval" ;;
|
winVer="windows-11-iot-enterprise-ltsc-eval" ;;
|
||||||
"win2025-eval" )
|
"win2025-eval" )
|
||||||
enterprise_type="server"
|
type="server"
|
||||||
windows_version="windows-server-2025" ;;
|
winVer="windows-server-2025" ;;
|
||||||
"win2022-eval" )
|
"win2022-eval" )
|
||||||
enterprise_type="server"
|
type="server"
|
||||||
windows_version="windows-server-2022" ;;
|
winVer="windows-server-2022" ;;
|
||||||
"win2019-hv" )
|
"win2019-hv" )
|
||||||
enterprise_type="server"
|
type="server"
|
||||||
windows_version="hyper-v-server-2019" ;;
|
winVer="hyper-v-server-2019" ;;
|
||||||
"win2019-eval" )
|
"win2019-eval" )
|
||||||
enterprise_type="server"
|
type="server"
|
||||||
windows_version="windows-server-2019" ;;
|
winVer="windows-server-2019" ;;
|
||||||
"win2016-eval" )
|
"win2016-eval" )
|
||||||
enterprise_type="server"
|
type="server"
|
||||||
windows_version="windows-server-2016" ;;
|
winVer="windows-server-2016" ;;
|
||||||
"win2012r2-eval" )
|
"win2012r2-eval" )
|
||||||
enterprise_type="server"
|
type="server"
|
||||||
windows_version="windows-server-2012-r2" ;;
|
winVer="windows-server-2012-r2" ;;
|
||||||
* )
|
* )
|
||||||
error "Invalid VERSION specified, value \"$id\" is not recognized!" && return 1 ;;
|
error "Invalid VERSION specified, value \"$id\" is not recognized!" && return 1 ;;
|
||||||
esac
|
esac
|
||||||
|
|
||||||
user_agent=$(get_agent)
|
agent=$(getAgent)
|
||||||
culture=$(getLanguage "$lang" "culture")
|
culture=$(getLanguage "$lang" "culture")
|
||||||
|
|
||||||
local country="${culture#*-}"
|
local country="${culture#*-}"
|
||||||
local iso_download_link=""
|
local link=""
|
||||||
local iso_download_links=""
|
local links=""
|
||||||
local iso_download_page_html=""
|
local page=""
|
||||||
local url="https://www.microsoft.com/en-us/evalcenter/download-$windows_version"
|
local url="https://www.microsoft.com/en-us/evalcenter/download-$winVer"
|
||||||
|
|
||||||
enabled "$DEBUG" && echo "Parsing download page: ${url}"
|
enabled "$DEBUG" && echo "Parsing download page: ${url}"
|
||||||
iso_download_page_html=$(curl --silent --max-time 30 --user-agent "$user_agent" --location --max-filesize 1M --fail --proto =https --tlsv1.2 --http1.1 -- "$url") || {
|
page=$(curl --silent --max-time 30 --user-agent "$agent" --location --max-filesize 1M --fail --proto =https --tlsv1.2 --http1.1 -- "$url") || {
|
||||||
handle_curl_error "$?" "Microsoft"
|
handleCurlError "$?" "Microsoft"
|
||||||
return $?
|
return $?
|
||||||
}
|
}
|
||||||
|
|
||||||
if ! [ "$iso_download_page_html" ]; then
|
if ! [ "$page" ]; then
|
||||||
# This should only happen if there's been some change to where this download page is located
|
# This should only happen if there's been some change to where this download page is located
|
||||||
error "Windows server download page gave us an empty response"
|
error "Windows server download page gave us an empty response"
|
||||||
return 1
|
return 1
|
||||||
@@ -293,11 +294,11 @@ download_windows_eval() {
|
|||||||
|
|
||||||
filter="https://go.microsoft.com/fwlink/?linkid=[0-9]\+&clcid=0x[0-9a-z]\+&culture=${culture,,}&country=${country,,}"
|
filter="https://go.microsoft.com/fwlink/?linkid=[0-9]\+&clcid=0x[0-9a-z]\+&culture=${culture,,}&country=${country,,}"
|
||||||
|
|
||||||
if ! echo "$iso_download_page_html" | grep -io "$filter" > /dev/null; then
|
if ! echo "$page" | grep -io "$filter" > /dev/null; then
|
||||||
filter="https://go.microsoft.com/fwlink/p/?linkid=[0-9]\+&clcid=0x[0-9a-z]\+&culture=${culture,,}&country=${country,,}"
|
filter="https://go.microsoft.com/fwlink/p/?linkid=[0-9]\+&clcid=0x[0-9a-z]\+&culture=${culture,,}&country=${country,,}"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
iso_download_links=$(echo "$iso_download_page_html" | grep -io "$filter") || {
|
links=$(echo "$page" | grep -io "$filter") || {
|
||||||
# This should only happen if there's been some change to the download endpoint web address
|
# This should only happen if there's been some change to the download endpoint web address
|
||||||
if [[ "${lang,,}" == "en" || "${lang,,}" == "en-"* ]]; then
|
if [[ "${lang,,}" == "en" || "${lang,,}" == "en-"* ]]; then
|
||||||
error "Windows server download page gave us no download link!"
|
error "Windows server download page gave us no download link!"
|
||||||
@@ -308,60 +309,60 @@ download_windows_eval() {
|
|||||||
return 1
|
return 1
|
||||||
}
|
}
|
||||||
|
|
||||||
case "$enterprise_type" in
|
case "$type" in
|
||||||
"iot" | "ltsc" )
|
"iot" | "ltsc" )
|
||||||
case "${PLATFORM,,}" in
|
case "${PLATFORM,,}" in
|
||||||
"x64" )
|
"x64" )
|
||||||
if [[ "$windows_version" != "windows-10"* ]]; then
|
if [[ "$winVer" != "windows-10"* ]]; then
|
||||||
iso_download_link=$(echo "$iso_download_links" | head -n 1)
|
link=$(echo "$links" | head -n 1)
|
||||||
else
|
else
|
||||||
iso_download_link=$(echo "$iso_download_links" | head -n 4 | tail -n 1)
|
link=$(echo "$links" | head -n 4 | tail -n 1)
|
||||||
fi ;;
|
fi ;;
|
||||||
"arm64" )
|
"arm64" )
|
||||||
iso_download_link=$(echo "$iso_download_links" | head -n 2 | tail -n 1) ;;
|
link=$(echo "$links" | head -n 2 | tail -n 1) ;;
|
||||||
esac ;;
|
esac ;;
|
||||||
"enterprise" )
|
"enterprise" )
|
||||||
case "${PLATFORM,,}" in
|
case "${PLATFORM,,}" in
|
||||||
"x64" )
|
"x64" )
|
||||||
if [[ "$windows_version" != "windows-10"* ]]; then
|
if [[ "$winVer" != "windows-10"* ]]; then
|
||||||
iso_download_link=$(echo "$iso_download_links" | head -n 1)
|
link=$(echo "$links" | head -n 1)
|
||||||
else
|
else
|
||||||
iso_download_link=$(echo "$iso_download_links" | head -n 2 | tail -n 1)
|
link=$(echo "$links" | head -n 2 | tail -n 1)
|
||||||
fi ;;
|
fi ;;
|
||||||
"arm64" )
|
"arm64" )
|
||||||
iso_download_link=$(echo "$iso_download_links" | head -n 2 | tail -n 1) ;;
|
link=$(echo "$links" | head -n 2 | tail -n 1) ;;
|
||||||
esac ;;
|
esac ;;
|
||||||
"server" )
|
"server" )
|
||||||
case "${PLATFORM,,}" in
|
case "${PLATFORM,,}" in
|
||||||
"x64" )
|
"x64" )
|
||||||
iso_download_link=$(echo "$iso_download_links" | head -n 1) ;;
|
link=$(echo "$links" | head -n 1) ;;
|
||||||
esac ;;
|
esac ;;
|
||||||
* )
|
* )
|
||||||
error "Invalid type specified, value \"$enterprise_type\" is not recognized!" && return 1 ;;
|
error "Invalid type specified, value \"$type\" is not recognized!" && return 1 ;;
|
||||||
esac
|
esac
|
||||||
|
|
||||||
[ -z "$iso_download_link" ] && error "Could not parse download link from page!" && return 1
|
[ -z "$link" ] && error "Could not parse download link from page!" && return 1
|
||||||
|
|
||||||
# Follow redirect so proceeding log message is useful
|
# Follow redirect so proceeding log message is useful
|
||||||
# This is a request we make that Fido doesn't
|
# This is a request we make that Fido doesn't
|
||||||
|
|
||||||
iso_download_link=$(curl --silent --max-time 30 --user-agent "$user_agent" --location --output /dev/null --silent --write-out "%{url_effective}" --head --fail --proto =https --tlsv1.2 --http1.1 -- "$iso_download_link") || {
|
link=$(curl --silent --max-time 30 --user-agent "$agent" --location --output /dev/null --silent --write-out "%{url_effective}" --head --fail --proto =https --tlsv1.2 --http1.1 -- "$link") || {
|
||||||
# This should only happen if the Microsoft servers are down
|
# This should only happen if the Microsoft servers are down
|
||||||
handle_curl_error "$?" "Microsoft"
|
handleCurlError "$?" "Microsoft"
|
||||||
return $?
|
return $?
|
||||||
}
|
}
|
||||||
|
|
||||||
case "${PLATFORM,,}" in
|
case "${PLATFORM,,}" in
|
||||||
"x64" )
|
"x64" )
|
||||||
if [[ "${iso_download_link,,}" != *"x64"* ]]; then
|
if [[ "${link,,}" != *"x64"* ]]; then
|
||||||
echo "Found download link: $iso_download_link"
|
echo "Found download link: $link"
|
||||||
error "Download link is for the wrong platform? Please report this at $SUPPORT/issues"
|
error "Download link is for the wrong platform? Please report this at $SUPPORT/issues"
|
||||||
return 1
|
return 1
|
||||||
fi ;;
|
fi ;;
|
||||||
"arm64" )
|
"arm64" )
|
||||||
if [[ "${iso_download_link,,}" != *"a64"* && "${iso_download_link,,}" != *"arm64"* ]]; then
|
if [[ "${link,,}" != *"a64"* && "${link,,}" != *"arm64"* ]]; then
|
||||||
if enabled "$DEBUG"; then
|
if enabled "$DEBUG"; then
|
||||||
echo "Found download link: $iso_download_link"
|
echo "Found download link: $link"
|
||||||
echo "Link for ARM platform currently not available!"
|
echo "Link for ARM platform currently not available!"
|
||||||
fi
|
fi
|
||||||
return 1
|
return 1
|
||||||
@@ -370,12 +371,12 @@ download_windows_eval() {
|
|||||||
|
|
||||||
if enabled "$DEBUG" && enabled "$VERIFY" && [[ "${lang,,}" == "en"* ]]; then
|
if enabled "$DEBUG" && enabled "$VERIFY" && [[ "${lang,,}" == "en"* ]]; then
|
||||||
compare=$(getMido "$id" "$lang" "")
|
compare=$(getMido "$id" "$lang" "")
|
||||||
if [[ "${iso_download_link,,}" != "${compare,,}" ]]; then
|
if [[ "${link,,}" != "${compare,,}" ]]; then
|
||||||
echo "Retrieved link does not match the fixed link: $compare"
|
echo "Retrieved link does not match the fixed link: $compare"
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
MIDO_URL="$iso_download_link"
|
MIDO_URL="$link"
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -413,13 +414,13 @@ getWindows() {
|
|||||||
|
|
||||||
case "${version,,}" in
|
case "${version,,}" in
|
||||||
"win11${PLATFORM,,}" )
|
"win11${PLATFORM,,}" )
|
||||||
download_windows "$version" "$lang" "$edition" && return 0
|
downloadWindows "$version" "$lang" "$edition" && return 0
|
||||||
;;
|
;;
|
||||||
"win11${PLATFORM,,}-enterprise"* )
|
"win11${PLATFORM,,}-enterprise"* )
|
||||||
download_windows_eval "$version" "$lang" "$edition" && return 0
|
downloadWindowsEval "$version" "$lang" "$edition" && return 0
|
||||||
;;
|
;;
|
||||||
"win2025-eval" | "win2022-eval" | "win2019-eval" | "win2019-hv" | "win2016-eval" | "win2012r2-eval" )
|
"win2025-eval" | "win2022-eval" | "win2019-eval" | "win2019-hv" | "win2016-eval" | "win2012r2-eval" )
|
||||||
download_windows_eval "$version" "$lang" "$edition" && return 0
|
downloadWindowsEval "$version" "$lang" "$edition" && return 0
|
||||||
;;
|
;;
|
||||||
"win2008r2" | "win81${PLATFORM,,}"* | "win10${PLATFORM,,}-enterprise"* )
|
"win2008r2" | "win81${PLATFORM,,}"* | "win10${PLATFORM,,}-enterprise"* )
|
||||||
;;
|
;;
|
||||||
@@ -506,6 +507,16 @@ getCatalog() {
|
|||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getXmlTag() {
|
||||||
|
|
||||||
|
local tag="$1"
|
||||||
|
local file="$2"
|
||||||
|
|
||||||
|
xmllint --nonet --xpath "//$tag" "$file" 2>/dev/null | sed -E -e "s/<[\/]?$tag>//g" || true
|
||||||
|
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
getESD() {
|
getESD() {
|
||||||
|
|
||||||
local dir="$1"
|
local dir="$1"
|
||||||
@@ -515,6 +526,10 @@ getESD() {
|
|||||||
local rc=0
|
local rc=0
|
||||||
local file result culture
|
local file result culture
|
||||||
local language edition catalog
|
local language edition catalog
|
||||||
|
local xmlFile="products.xml"
|
||||||
|
local esdFile="esd_edition.xml"
|
||||||
|
local filterFile="products_filter.xml"
|
||||||
|
local query
|
||||||
|
|
||||||
file=$(getCatalog "$version" "file")
|
file=$(getCatalog "$version" "file")
|
||||||
catalog=$(getCatalog "$version" "url")
|
catalog=$(getCatalog "$version" "url")
|
||||||
@@ -522,7 +537,8 @@ getESD() {
|
|||||||
edition=$(getCatalog "$version" "edition")
|
edition=$(getCatalog "$version" "edition")
|
||||||
|
|
||||||
if [ -z "$file" ] || [ -z "$catalog" ]; then
|
if [ -z "$file" ] || [ -z "$catalog" ]; then
|
||||||
error "Invalid VERSION specified, value \"$version\" is not recognized!" && return 1
|
error "Invalid VERSION specified, value \"$version\" is not recognized!"
|
||||||
|
return 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
local msg="Downloading catalog from the Microsoft servers..."
|
local msg="Downloading catalog from the Microsoft servers..."
|
||||||
@@ -531,13 +547,10 @@ getESD() {
|
|||||||
rm -rf "$dir"
|
rm -rf "$dir"
|
||||||
|
|
||||||
if ! makeDir "$dir"; then
|
if ! makeDir "$dir"; then
|
||||||
error "Failed to create directory \"$dir\" !" && return 1
|
error "Failed to create directory \"$dir\" !"
|
||||||
|
return 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
local xFile="products.xml"
|
|
||||||
local eFile="esd_edition.xml"
|
|
||||||
local fFile="products_filter.xml"
|
|
||||||
|
|
||||||
{ wget "$catalog" -O "$dir/$file" -q --timeout=30 --no-http-keep-alive; rc=$?; } || :
|
{ wget "$catalog" -O "$dir/$file" -q --timeout=30 --no-http-keep-alive; rc=$?; } || :
|
||||||
|
|
||||||
msg="Failed to download $catalog"
|
msg="Failed to download $catalog"
|
||||||
@@ -548,8 +561,8 @@ getESD() {
|
|||||||
|
|
||||||
if [[ "$file" == *".xml" ]]; then
|
if [[ "$file" == *".xml" ]]; then
|
||||||
|
|
||||||
if ! mv -f "$dir/$file" "$dir/$xFile"; then
|
if ! mv -f "$dir/$file" "$dir/$xmlFile"; then
|
||||||
error "Failed to rename $file to $xFile."
|
error "Failed to rename $file to $xmlFile."
|
||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
@@ -559,65 +572,68 @@ getESD() {
|
|||||||
cd "$dir" || exit 1
|
cd "$dir" || exit 1
|
||||||
cabextract "$file" > /dev/null
|
cabextract "$file" > /dev/null
|
||||||
); then
|
); then
|
||||||
error "Failed to extract $file!" && return 1
|
error "Failed to extract $file!"
|
||||||
|
return 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [ ! -s "$dir/$xFile" ]; then
|
if [ ! -s "$dir/$xmlFile" ]; then
|
||||||
error "Failed to find $xFile in $file!" && return 1
|
error "Failed to find $xmlFile in $file!"
|
||||||
|
return 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
local edQuery='//File[Architecture="'${PLATFORM,,}'"]'"${edition}"''
|
query='//File[Architecture="'${PLATFORM,,}'"]'"${edition}"''
|
||||||
result=$(xmllint --nonet --xpath "${edQuery}" "$dir/$xFile" 2>/dev/null || true)
|
result=$(xmllint --nonet --xpath "${query}" "$dir/$xmlFile" 2>/dev/null || true)
|
||||||
|
|
||||||
if [ -z "$result" ]; then
|
if [ -z "$result" ]; then
|
||||||
|
|
||||||
edQuery='//File[Architecture="'${PLATFORM^^}'"]'"${edition}"''
|
query='//File[Architecture="'${PLATFORM^^}'"]'"${edition}"''
|
||||||
|
result=$(xmllint --nonet --xpath "${query}" "$dir/$xmlFile" 2>/dev/null || true)
|
||||||
result=$(xmllint --nonet --xpath "${edQuery}" "$dir/$xFile" 2>/dev/null || true)
|
|
||||||
|
|
||||||
if [ -z "$result" ]; then
|
if [ -z "$result" ]; then
|
||||||
desc=$(printEdition "$version" "$desc")
|
desc=$(printEdition "$version" "$desc")
|
||||||
language=$(getLanguage "$lang" "desc")
|
language=$(getLanguage "$lang" "desc")
|
||||||
error "No download link available for $desc!" && return 1
|
error "No download link available for $desc!"
|
||||||
|
return 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
echo -e '<Catalog>' > "$dir/$fFile"
|
echo -e '<Catalog>' > "$dir/$filterFile"
|
||||||
echo "$result" >> "$dir/$fFile"
|
echo "$result" >> "$dir/$filterFile"
|
||||||
echo -e '</Catalog>'>> "$dir/$fFile"
|
echo -e '</Catalog>'>> "$dir/$filterFile"
|
||||||
|
|
||||||
result=$(xmllint --nonet --xpath "//File[LanguageCode=\"${culture,,}\"]" "$dir/$fFile" 2>/dev/null || true)
|
result=$(xmllint --nonet --xpath "//File[LanguageCode=\"${culture,,}\"]" "$dir/$filterFile" 2>/dev/null || true)
|
||||||
|
|
||||||
if [ -z "$result" ]; then
|
if [ -z "$result" ]; then
|
||||||
desc=$(printEdition "$version" "$desc")
|
desc=$(printEdition "$version" "$desc")
|
||||||
language=$(getLanguage "$lang" "desc")
|
language=$(getLanguage "$lang" "desc")
|
||||||
error "No download in the $language language available for $desc!" && return 1
|
error "No download in the $language language available for $desc!"
|
||||||
|
return 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
echo "$result" > "$dir/$eFile"
|
echo "$result" > "$dir/$esdFile"
|
||||||
|
|
||||||
tag="FilePath"
|
ESD=$(getXmlTag "FilePath" "$dir/$esdFile")
|
||||||
ESD=$(xmllint --nonet --xpath "//$tag" "$dir/$eFile" 2>/dev/null | sed -E -e "s/<[\/]?$tag>//g" || true)
|
|
||||||
|
|
||||||
if [ -z "$ESD" ]; then
|
if [ -z "$ESD" ]; then
|
||||||
error "Failed to find ESD URL in $eFile!" && return 1
|
error "Failed to find ESD URL in $esdFile!"
|
||||||
|
return 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
tag="Sha1"
|
ESD_SUM=$(getXmlTag "Sha1" "$dir/$esdFile")
|
||||||
ESD_SUM=$(xmllint --nonet --xpath "//$tag" "$dir/$eFile" 2>/dev/null | sed -E -e "s/<[\/]?$tag>//g" || true)
|
|
||||||
|
|
||||||
if [ -z "$ESD_SUM" ]; then
|
if [ -z "$ESD_SUM" ]; then
|
||||||
error "Failed to find ESD checksum in $eFile!" && return 1
|
error "Failed to find ESD checksum in $esdFile!"
|
||||||
|
return 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
tag="Size"
|
ESD_SIZE=$(getXmlTag "Size" "$dir/$esdFile")
|
||||||
ESD_SIZE=$(xmllint --nonet --xpath "//$tag" "$dir/$eFile" 2>/dev/null | sed -E -e "s/<[\/]?$tag>//g" || true)
|
|
||||||
|
|
||||||
if [ -z "$ESD_SIZE" ]; then
|
if [ -z "$ESD_SIZE" ]; then
|
||||||
error "Failed to find ESD filesize in $eFile!" && return 1
|
error "Failed to find ESD filesize in $esdFile!"
|
||||||
|
return 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
rm -rf "$dir"
|
rm -rf "$dir"
|
||||||
@@ -690,7 +706,7 @@ downloadFile() {
|
|||||||
local msg="Downloading $desc"
|
local msg="Downloading $desc"
|
||||||
local rc total total_gb progress domain dots agent space folder
|
local rc total total_gb progress domain dots agent space folder
|
||||||
|
|
||||||
agent=$(get_agent)
|
agent=$(getAgent)
|
||||||
|
|
||||||
if [ -n "$size" ] && [[ "$size" != "0" ]]; then
|
if [ -n "$size" ] && [[ "$size" != "0" ]]; then
|
||||||
|
|
||||||
@@ -740,14 +756,16 @@ downloadFile() {
|
|||||||
total_gb=$(formatBytes "$total")
|
total_gb=$(formatBytes "$total")
|
||||||
|
|
||||||
if [ "$total" -lt 100000000 ]; then
|
if [ "$total" -lt 100000000 ]; then
|
||||||
error "Invalid download link: $url (is only $total_gb ?). Please report this at $SUPPORT/issues" && return 1
|
error "Invalid download link: $url (is only $total_gb ?). Please report this at $SUPPORT/issues"
|
||||||
|
return 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
verifyFile "$iso" "$size" "$total" "$sum" || return 1
|
verifyFile "$iso" "$size" "$total" "$sum" || return 1
|
||||||
|
|
||||||
isCompressed "$url" && UNPACK="Y"
|
isCompressed "$url" && UNPACK="Y"
|
||||||
|
|
||||||
html "Download finished successfully..." && return 0
|
html "Download finished successfully..."
|
||||||
|
return 0
|
||||||
fi
|
fi
|
||||||
|
|
||||||
msg="Failed to download $url"
|
msg="Failed to download $url"
|
||||||
@@ -802,7 +820,7 @@ downloadImage() {
|
|||||||
local tried="n"
|
local tried="n"
|
||||||
local success="n"
|
local success="n"
|
||||||
local seconds="5"
|
local seconds="5"
|
||||||
local url sum size base desc language
|
local url sum size base desc language i
|
||||||
|
|
||||||
if [[ "${version,,}" == "http"* ]]; then
|
if [[ "${version,,}" == "http"* ]]; then
|
||||||
|
|
||||||
@@ -814,7 +832,8 @@ downloadImage() {
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
if ! validVersion "$version" "en"; then
|
if ! validVersion "$version" "en"; then
|
||||||
error "Invalid VERSION specified, value \"$version\" is not recognized!" && return 1
|
error "Invalid VERSION specified, value \"$version\" is not recognized!"
|
||||||
|
return 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
desc=$(printVersion "$version" "")
|
desc=$(printVersion "$version" "")
|
||||||
@@ -823,7 +842,8 @@ downloadImage() {
|
|||||||
language=$(getLanguage "$lang" "desc")
|
language=$(getLanguage "$lang" "desc")
|
||||||
if ! validVersion "$version" "$lang"; then
|
if ! validVersion "$version" "$lang"; then
|
||||||
desc=$(printEdition "$version" "$desc")
|
desc=$(printEdition "$version" "$desc")
|
||||||
error "The $language language version of $desc is not available, please switch to English." && return 1
|
error "The $language language version of $desc is not available, please switch to English."
|
||||||
|
return 1
|
||||||
fi
|
fi
|
||||||
desc+=" in $language"
|
desc+=" in $language"
|
||||||
fi
|
fi
|
||||||
|
|||||||
Reference in New Issue
Block a user