Compare commits

..

1 Commits

Author SHA1 Message Date
a2ec23d667
sha256 sanity
Shorten files names
Exclude express and differential files
Only append hash suffix for duplicate files names (e.g. 22458 LPs for some langs)
2021-10-16 15:28:11 +03:00
479 changed files with 375 additions and 628 deletions

1
.gitignore vendored Normal file
View File

@ -0,0 +1 @@
shared/cookie.json

View File

@ -17,8 +17,6 @@ limitations under the License.
require_once dirname(__FILE__).'/shared/main.php'; require_once dirname(__FILE__).'/shared/main.php';
require_once dirname(__FILE__).'/shared/requests.php'; require_once dirname(__FILE__).'/shared/requests.php';
require_once dirname(__FILE__).'/shared/cache.php';
require_once dirname(__FILE__).'/shared/fileinfo.php';
require_once dirname(__FILE__).'/listid.php'; require_once dirname(__FILE__).'/listid.php';
function uupFetchUpd( function uupFetchUpd(
@ -39,18 +37,14 @@ function uupFetchUpd(
$flight = 'Active'; $flight = 'Active';
if($build == 'latest' || (!$build)) { if($build == 'latest' || (!$build)) {
$builds = array('22000.1'); $builds = array('17134.1');
$ids = uupListIds(); $ids = uupListIds();
if(isset($ids['error'])) { if(isset($ids['error'])) {
$ids['builds'] = array(); $ids['builds'] = array();
} }
if(empty($ids['builds'])) {
$build = $builds[0];
} else {
$build = $ids['builds'][0]['build']; $build = $ids['builds'][0]['build'];
}
unset($builds, $ids); unset($builds, $ids);
} }
@ -63,7 +57,7 @@ function uupFetchUpd(
return array('error' => 'UNKNOWN_ARCH'); return array('error' => 'UNKNOWN_ARCH');
} }
if(!($ring == 'CANARY' || $ring == 'DEV' || $ring == 'BETA' || $ring == 'RELEASEPREVIEW' || $ring == 'WIF' || $ring == 'WIS' || $ring == 'RP' || $ring == 'RETAIL' || $ring == 'MSIT')) { if(!($ring == 'DEV' || $ring == 'BETA' || $ring == 'RELEASEPREVIEW' || $ring == 'WIF' || $ring == 'WIS' || $ring == 'RP' || $ring == 'RETAIL' || $ring == 'MSIT')) {
return array('error' => 'UNKNOWN_RING'); return array('error' => 'UNKNOWN_RING');
} }
@ -96,22 +90,45 @@ function uupFetchUpd(
$type = 'Production'; $type = 'Production';
} }
$res = "api-fetch-$arch-$ring-$flight-$build-$minor-$sku-$type"; $cacheHash = hash('sha256', strtolower("api-fetch-$arch-$ring-$flight-$build-$minor-$sku-$type"));
$cache = new UupDumpCache($res); $cached = 0;
$fromCache = $cache->get();
if($fromCache !== false) return $fromCache;
consoleLogger('Fetching information from the server...'); if(file_exists('cache/'.$cacheHash.'.json.gz') && $cacheRequests == 1) {
$composerArgs = [$arch, $flight, $ring, $build, $sku, $type]; $cache = @gzdecode(@file_get_contents('cache/'.$cacheHash.'.json.gz'));
$out = sendWuPostRequestHelper('client', 'composeFetchUpdRequest', $composerArgs); $cache = json_decode($cache, 1);
if($out['error'] != 200) {
consoleLogger('The request has failed'); if(!empty($cache['content']) && ($cache['expires'] > time())) {
return array('error' => 'WU_REQUEST_FAILED'); consoleLogger('Using cached response...');
$out = $cache['content'];
$cached = 1;
} else {
$cached = 0;
} }
$out = html_entity_decode($out['out']); unset($cache);
}
if(!$cached) {
consoleLogger('Fetching information from the server...');
$postData = composeFetchUpdRequest(uupDevice(), uupEncryptedData(), $arch, $flight, $ring, $build, $sku, $type);
$out = sendWuPostRequest('https://fe3cr.delivery.mp.microsoft.com/ClientWebService/client.asmx', $postData);
$out = html_entity_decode($out);
consoleLogger('Information has been successfully fetched.'); consoleLogger('Information has been successfully fetched.');
if($cacheRequests == 1) {
$cache = array(
'expires' => time()+120,
'content' => $out,
);
if(!file_exists('cache')) mkdir('cache');
@file_put_contents('cache/'.$cacheHash.'.json.gz', gzencode(json_encode($cache)."\n"));
unset($cache);
}
}
preg_match_all('/<UpdateInfo>.*?<\/UpdateInfo>/', $out, $updateInfos); preg_match_all('/<UpdateInfo>.*?<\/UpdateInfo>/', $out, $updateInfos);
$updateInfo = preg_grep('/<IsLeaf>true<\/IsLeaf>/', $updateInfos[0]); $updateInfo = preg_grep('/<IsLeaf>true<\/IsLeaf>/', $updateInfos[0]);
sort($updateInfo); sort($updateInfo);
@ -143,7 +160,7 @@ function uupFetchUpd(
return array('error' => 'EMPTY_FILELIST'); return array('error' => 'EMPTY_FILELIST');
} }
$data = [ return array(
'apiVersion' => uupApiVersion(), 'apiVersion' => uupApiVersion(),
'updateId' => $updateArray[0]['updateId'], 'updateId' => $updateArray[0]['updateId'],
'updateTitle' => $updateArray[0]['updateTitle'], 'updateTitle' => $updateArray[0]['updateTitle'],
@ -151,13 +168,7 @@ function uupFetchUpd(
'arch' => $updateArray[0]['arch'], 'arch' => $updateArray[0]['arch'],
'fileWrite' => $updateArray[0]['fileWrite'], 'fileWrite' => $updateArray[0]['fileWrite'],
'updateArray' => $updateArray, 'updateArray' => $updateArray,
]; );
if($cacheRequests == 1) {
$cache->put($data, 120);
}
return $data;
} }
function parseFetchUpdate($updateInfo, $out, $arch, $ring, $flight, $build, $sku, $type) { function parseFetchUpdate($updateInfo, $out, $arch, $ring, $flight, $build, $sku, $type) {
@ -226,10 +237,8 @@ function parseFetchUpdate($updateInfo, $out, $arch, $ring, $flight, $build, $sku
$updateTitle = preg_replace("/ ?\d{4}-\d{2}\D ?| ?$foundArch ?| ?x64 ?/i", '', $updateTitle); $updateTitle = preg_replace("/ ?\d{4}-\d{2}\D ?| ?$foundArch ?| ?x64 ?/i", '', $updateTitle);
if($foundType == 'server') { if($foundType == 'server')
$updateTitle = str_replace('Windows 10', 'Windows Server', $updateTitle); $updateTitle = str_replace('Windows 10', 'Windows Server', $updateTitle);
$updateTitle = str_replace('Windows 11', 'Windows Server', $updateTitle);
}
if($sku == 406) if($sku == 406)
$updateTitle = str_replace('Microsoft server operating system', 'Azure Stack HCI', $updateTitle); $updateTitle = str_replace('Microsoft server operating system', 'Azure Stack HCI', $updateTitle);
@ -291,16 +300,16 @@ function parseFetchUpdate($updateInfo, $out, $arch, $ring, $flight, $build, $sku
return array('error' => 'BROKEN_UPDATE'); return array('error' => 'BROKEN_UPDATE');
} }
$isCorpnet = preg_match('/Corpnet Required/i', $updateTitle); if(preg_match('/Corpnet Required/i', $updateTitle)) {
if($isCorpnet && !uupApiConfigIsTrue('allow_corpnet')) {
consoleLogger('Skipping corpnet only update...'); consoleLogger('Skipping corpnet only update...');
return array('error' => 'CORPNET_ONLY_UPDATE'); return array('error' => 'CORPNET_ONLY_UPDATE');
} }
$fileWrite = 'NO_SAVE'; $fileWrite = 'NO_SAVE';
if(!uupApiFileInfoExists($updateId)) { if(!file_exists('fileinfo/'.$updateString.'.json')) {
consoleLogger('WARNING: This build is NOT in the database. It will be saved now.'); consoleLogger('WARNING: This build is NOT in the database. It will be saved now.');
consoleLogger('Parsing information to write...'); consoleLogger('Parsing information to write...');
if(!file_exists('fileinfo')) mkdir('fileinfo');
$fileList = preg_replace('/<Files>|<\/Files>/', '', $fileList[0]); $fileList = preg_replace('/<Files>|<\/Files>/', '', $fileList[0]);
preg_match_all('/<File.*?<\/File>/', $fileList, $fileList); preg_match_all('/<File.*?<\/File>/', $fileList, $fileList);
@ -358,11 +367,10 @@ function parseFetchUpdate($updateInfo, $out, $arch, $ring, $flight, $build, $sku
consoleLogger('Successfully parsed the information.'); consoleLogger('Successfully parsed the information.');
consoleLogger('Writing new build information to the disk...'); consoleLogger('Writing new build information to the disk...');
$success = uupApiWriteFileinfo($updateString, $temp); $success = file_put_contents('fileinfo/'.$updateString.'.json', json_encode($temp)."\n");
if($success) { if($success) {
consoleLogger('Successfully written build information to the disk.'); consoleLogger('Successfully written build information to the disk.');
$fileWrite = 'INFO_WRITTEN'; $fileWrite = 'INFO_WRITTEN';
uupApiPrivateInvalidateFileinfoCache();
} else { } else {
consoleLogger('An error has occured while writing the information to the disk.'); consoleLogger('An error has occured while writing the information to the disk.');
} }

179
get.php
View File

@ -18,8 +18,6 @@ limitations under the License.
require_once dirname(__FILE__).'/shared/main.php'; require_once dirname(__FILE__).'/shared/main.php';
require_once dirname(__FILE__).'/shared/requests.php'; require_once dirname(__FILE__).'/shared/requests.php';
require_once dirname(__FILE__).'/shared/packs.php'; require_once dirname(__FILE__).'/shared/packs.php';
require_once dirname(__FILE__).'/shared/cache.php';
require_once dirname(__FILE__).'/shared/fileinfo.php';
/* /*
$updateId = Update Identifier $updateId = Update Identifier
@ -47,13 +45,7 @@ function uupGetFiles(
return array('error' => 'INCORRECT_ID'); return array('error' => 'INCORRECT_ID');
} }
$edition = is_array($desiredEdition) ? implode('_', $desiredEdition) : $desiredEdition; $info = @file_get_contents('fileinfo/'.$updateId.'.json');
$res = "api-get-{$updateId}_{$usePack}_{$edition}_{$requestType}";
$cache = new UupDumpCache($res);
$fromCache = $cache->get();
if($fromCache !== false) return $fromCache;
$info = uupApiReadFileinfo($updateId);
if(empty($info)) { if(empty($info)) {
$info = array( $info = array(
'ring' => 'WIF', 'ring' => 'WIF',
@ -63,6 +55,8 @@ function uupGetFiles(
'sku' => '48', 'sku' => '48',
'files' => array(), 'files' => array(),
); );
} else {
$info = json_decode($info, true);
} }
if(isset($info['build'])) { if(isset($info['build'])) {
@ -85,8 +79,6 @@ function uupGetFiles(
} }
} }
$appEdition = 0;
if(!is_array($desiredEdition)) { if(!is_array($desiredEdition)) {
$desiredEdition = strtoupper($desiredEdition); $desiredEdition = strtoupper($desiredEdition);
$fileListSource = $desiredEdition; $fileListSource = $desiredEdition;
@ -112,19 +104,13 @@ function uupGetFiles(
case 'UPDATEONLY': break; case 'UPDATEONLY': break;
case 'APP': $appEdition = 1;
case 'APP_MOMENT': $appEdition = 1;
default: default:
if(!isset($genPack[$usePack][$desiredEdition])) { if(!isset($genPack[$usePack][$desiredEdition])) {
return array('error' => 'UNSUPPORTED_COMBINATION'); return array('error' => 'UNSUPPORTED_COMBINATION');
} }
$fileListSource = 'GENERATEDPACKS';
$filesPacksList = $genPack[$usePack][$desiredEdition]; $filesPacksList = $genPack[$usePack][$desiredEdition];
if($desiredEdition == 'APP' && isset($genPack[$usePack]['APP_MOMENT'])) { $fileListSource = 'GENERATEDPACKS';
$filesPacksList = array_merge($filesPacksList, $genPack[$usePack]['APP_MOMENT']);
}
break; break;
} }
} else { } else {
@ -137,7 +123,6 @@ function uupGetFiles(
return array('error' => 'UNSUPPORTED_COMBINATION'); return array('error' => 'UNSUPPORTED_COMBINATION');
} }
if($edition == 'APP' || $edition == 'APP_MOMENT') $appEdition = 1;
$filesPacksList = array_merge($filesPacksList, $genPack[$usePack][$edition]); $filesPacksList = array_merge($filesPacksList, $genPack[$usePack][$edition]);
} }
} }
@ -153,7 +138,6 @@ function uupGetFiles(
$updateBuild = (isset($info['build'])) ? $info['build'] : 'UNKNOWN'; $updateBuild = (isset($info['build'])) ? $info['build'] : 'UNKNOWN';
$updateName = (isset($info['title'])) ? $info['title'] : 'Unknown update: '.$updateId; $updateName = (isset($info['title'])) ? $info['title'] : 'Unknown update: '.$updateId;
$sha256capable = isset($info['sha256ready']); $sha256capable = isset($info['sha256ready']);
$hasUpdates = false;
if(isset($info['releasetype'])) { if(isset($info['releasetype'])) {
$type = $info['releasetype']; $type = $info['releasetype'];
@ -180,34 +164,16 @@ function uupGetFiles(
if(isset($filesInfoList[$val])) unset($filesInfoList[$val]); if(isset($filesInfoList[$val])) unset($filesInfoList[$val]);
} }
$baseless = preg_grep('/^baseless_/i', array_keys($filesInfoList)); $baseless = preg_grep('/^baseless_|Windows10\.0-KB.*-EXPRESS|SSU-.*-EXPRESS/i', array_keys($filesInfoList));
foreach($baseless as $val) { foreach($baseless as $val) {
if(isset($filesInfoList[$val])) unset($filesInfoList[$val]); if(isset($filesInfoList[$val])) unset($filesInfoList[$val]);
} }
$expresscab = preg_grep('/Windows(10|11)\.0-KB.*-EXPRESS|SSU-.*-EXPRESS/i', array_keys($filesInfoList));
$expresspsf = array();
foreach($expresscab as $val) {
$name = preg_replace('/-EXPRESS.cab$/i', '', $val);
$expresspsf[] = $name;
if(isset($filesInfoList[$val])) unset($filesInfoList[$val]);
}
unset($index, $name, $expresscab);
foreach($expresspsf as $val) {
if(isset($filesInfoList[$val.'.cab'])) {
if(isset($filesInfoList[$val.'.psf'])) unset($filesInfoList[$val.'.psf']);
}
}
unset($expresspsf);
$psf = array_keys($filesInfoList); $psf = array_keys($filesInfoList);
$psf = preg_grep('/\.psf$/i', $psf); $psf = preg_grep('/\.psf$/i', $psf);
$psfk = preg_grep('/Windows(10|11)\.0-KB.*/i', $psf); $psfk = preg_grep('/Windows10\.0-KB.*/i', $psf);
$psfk = preg_grep('/.*-EXPRESS/i', $psfk, PREG_GREP_INVERT); $psfk = preg_grep('/.*-EXPRESS/i', $psfk, PREG_GREP_INVERT);
if($build < 17763) $psfk = preg_grep('/Windows(10|11)\.0-KB.*_\d\.psf$/i', $psfk, PREG_GREP_INVERT);
foreach($psfk as $key => $val) { foreach($psfk as $key => $val) {
if(isset($psf[$key])) unset($psf[$key]); if(isset($psf[$key])) unset($psf[$key]);
} }
@ -235,46 +201,24 @@ function uupGetFiles(
} }
unset($removeFiles); unset($removeFiles);
$msu = array_keys($filesInfoList);
$msu = preg_grep('/\.msu$/i', $msu);
$removeMSUs = array();
foreach($msu as $val) {
$name = preg_replace('/\.msu$/i', '', $val);
$removeMSUs[] = $name;
}
unset($index, $name, $msu);
$filesInfoKeys = array_keys($filesInfoList); $filesInfoKeys = array_keys($filesInfoList);
$updatesRegex = '/Windows(10|11)\.0-KB|SSU-.*?\....$/i';
switch($fileListSource) { switch($fileListSource) {
case 'UPDATEONLY': case 'UPDATEONLY':
$skipPackBuild = 1; $skipPackBuild = 1;
$removeFiles = preg_grep('/Windows(10|11)\.0-KB.*-baseless/i', $filesInfoKeys); $removeFiles = preg_grep('/Windows10\.0-KB.*-EXPRESS|Windows10\.0-KB.*-baseless|SSU-\d*?\.\d*?-.{3,5}-EXPRESS/i', $filesInfoKeys);
foreach($removeFiles as $val) { foreach($removeFiles as $val) {
if(isset($filesInfoList[$val])) unset($filesInfoList[$val]); if(isset($filesInfoList[$val])) unset($filesInfoList[$val]);
} }
unset($removeFiles); unset($removeFiles);
foreach($removeMSUs as $val) {
if(isset($filesInfoList[$val.'.cab']) && isset($filesInfoList[$val.'.msu'])) {
unset($filesInfoList[$val.'.msu']);
}
}
unset($removeMSUs);
$filesInfoKeys = array_keys($filesInfoList); $filesInfoKeys = array_keys($filesInfoList);
$temp = preg_grep('/.*?AggregatedMetadata.*?\.cab|.*?DesktopDeployment.*?\.cab/i', $filesInfoKeys);
$filesInfoKeys = preg_grep($updatesRegex, $filesInfoKeys); $filesInfoKeys = preg_grep('/Windows10\.0-KB|SSU-\d*?\.\d*?-.*?\.cab/i', $filesInfoKeys);
if(count($filesInfoKeys) == 0) { if(count($filesInfoKeys) == 0) {
return array('error' => 'NOT_CUMULATIVE_UPDATE'); return array('error' => 'NOT_CUMULATIVE_UPDATE');
} }
if($build > 21380) $filesInfoKeys = array_merge($filesInfoKeys, $temp);
unset($temp);
$hasUpdates = true;
break; break;
case 'WUBFILE': case 'WUBFILE':
@ -288,24 +232,8 @@ function uupGetFiles(
if($updateSku == 135) $uupCleanFunc = 'uupCleanHolo'; if($updateSku == 135) $uupCleanFunc = 'uupCleanHolo';
if($fileListSource == 'GENERATEDPACKS') { if($fileListSource == 'GENERATEDPACKS') {
foreach($removeMSUs as $val) { $temp = preg_grep('/Windows10\.0-KB.*-EXPRESS|Windows10\.0-KB.*-baseless|SSU-\d*?\.\d*?-.{3,5}-EXPRESS/i', $filesInfoKeys, PREG_GREP_INVERT);
if(isset($filesInfoList[$val.'.cab']) && isset($filesInfoList[$val.'.msu'])) { $temp = preg_grep('/Windows10\.0-KB|SSU-\d*?\.\d*?-.*?\.cab/i', $temp);
unset($filesInfoList[$val.'.msu']);
}
}
unset($removeMSUs);
$filesInfoKeys = array_keys($filesInfoList);
$temp = preg_grep('/Windows(10|11)\.0-KB.*-baseless/i', $filesInfoKeys, PREG_GREP_INVERT);
if($appEdition) {
$temp = preg_grep('/.*?AggregatedMetadata.*?\.cab|.*?DesktopDeployment.*?\.cab/i', $temp);
} else if($build > 21380) {
$temp = preg_grep('/Windows(10|11)\.0-KB|SSU-.*?\....$|.*?AggregatedMetadata.*?\.cab|.*?DesktopDeployment.*?\.cab/i', $temp);
} else {
$temp = preg_grep($updatesRegex, $temp);
}
$hasUpdates = !empty(preg_grep($updatesRegex, $temp));
$filesPacksList = array_merge($filesPacksList, $temp); $filesPacksList = array_merge($filesPacksList, $temp);
$newFiles = array(); $newFiles = array();
@ -357,7 +285,6 @@ function uupGetFiles(
$filesNew = array(); $filesNew = array();
foreach($filesInfoKeys as $val) { foreach($filesInfoKeys as $val) {
$filesNew[$val] = $filesInfoList[$val]; $filesNew[$val] = $filesInfoList[$val];
$filesNew[$val]['url'] = uupApiFixDownloadLink($filesInfoList[$val]['url']);
} }
$files = $filesNew; $files = $filesNew;
@ -365,53 +292,48 @@ function uupGetFiles(
consoleLogger('Successfully parsed the information.'); consoleLogger('Successfully parsed the information.');
$data = [ return array(
'apiVersion' => uupApiVersion(), 'apiVersion' => uupApiVersion(),
'updateName' => $updateName, 'updateName' => $updateName,
'arch' => $updateArch, 'arch' => $updateArch,
'build' => $updateBuild, 'build' => $updateBuild,
'sku' => $updateSku, 'sku' => $updateSku,
'hasUpdates' => $hasUpdates,
'files' => $files, 'files' => $files,
]; );
if($requestType > 0) {
$cacheData = $data;
$cache->put($cacheData, 30);
}
return $data;
} }
function uupGetOnlineFiles($updateId, $rev, $info, $cacheRequests, $type) { function uupGetOnlineFiles($updateId, $rev, $info, $cacheRequests, $type) {
$res = "api-get-online-{$updateId}_rev.$rev"; $cacheHash = hash('sha256', strtolower("api-get-${updateId}_rev.$rev"));
$cache = new UupDumpCache($res); $cached = 0;
$fromCache = $cache->get();
$cached = ($fromCache !== false);
if($cached) { if(file_exists('cache/'.$cacheHash.'.json.gz') && $cacheRequests == 1) {
$out = $fromCache['out']; $cache = @gzdecode(@file_get_contents('cache/'.$cacheHash.'.json.gz'));
$fetchTime = $fromCache['fetchTime']; $cache = json_decode($cache, 1);
if(!empty($cache['content']) && ($cache['expires'] > time())) {
consoleLogger('Using cached response...');
$out = $cache['content'];
$fetchTime = $cache['fetchTime'];
$cached = 1;
} else { } else {
$fetchTime = time(); $cached = 0;
consoleLogger('Fetching information from the server...');
$composerArgs = [$updateId, $info, $rev, $type];
$out = sendWuPostRequestHelper('clientSecured', 'composeFileGetRequest', $composerArgs);
if($out['error'] != 200) {
consoleLogger('The request has failed');
return array('error' => 'WU_REQUEST_FAILED');
} }
$out = $out['out']; unset($cache);
}
if(!$cached) {
$fetchTime = time();
consoleLogger('Fetching information from the server...');
$postData = composeFileGetRequest($updateId, uupDevice(), $info, $rev, $type);
$out = sendWuPostRequest('https://fe3cr.delivery.mp.microsoft.com/ClientWebService/client.asmx/secured', $postData);
consoleLogger('Information has been successfully fetched.'); consoleLogger('Information has been successfully fetched.');
} }
consoleLogger('Parsing information...'); consoleLogger('Parsing information...');
$xmlOut = @simplexml_load_string($out); $xmlOut = @simplexml_load_string($out);
if($xmlOut === false) { if($xmlOut === false) {
$cache->delete(); @unlink('cache/'.$cacheHash.'.json.gz');
return array('error' => 'XML_PARSE_ERROR'); return array('error' => 'XML_PARSE_ERROR');
} }
@ -459,11 +381,15 @@ function uupGetOnlineFiles($updateId, $rev, $info, $cacheRequests, $type) {
if($sha256capable) { if($sha256capable) {
$tempname = uupCleanSha256($name); $tempname = uupCleanSha256($name);
if(isset($files[$tempname])) { if(isset($files[$tempname])) {
if(preg_match('/\.cab$/i', $tempname)) {
if($size > $files[$tempname]['size']) { if($size > $files[$tempname]['size']) {
$smaller = uupAppendSha1($tempname, $files[$tempname]['sha1']); $express = 'baseless_'.$tempname;
$files[$smaller] = $files[$tempname]; $files[$express] = $files[$tempname];
unset($files[$tempname]); unset($files[$tempname]);
$newName = $tempname; $newName = $tempname;
} else {
$newName = 'baseless_'.$tempname;
}
} else { } else {
$newName = uupAppendSha1($tempname, $sha1); $newName = uupAppendSha1($tempname, $sha1);
} }
@ -507,12 +433,14 @@ function uupGetOnlineFiles($updateId, $rev, $info, $cacheRequests, $type) {
} }
if($cacheRequests == 1 && $cached == 0) { if($cacheRequests == 1 && $cached == 0) {
$cacheData = [ $cache = array(
'out' => $out, 'expires' => time()+90,
'content' => $out,
'fetchTime' => $fetchTime, 'fetchTime' => $fetchTime,
]; );
$cache->put($cacheData, 90); if(!file_exists('cache')) mkdir('cache');
@file_put_contents('cache/'.$cacheHash.'.json.gz', gzencode(json_encode($cache)."\n"));
} }
return $files; return $files;
@ -534,14 +462,24 @@ function uupGetOfflineFiles($info) {
$sha256 = isset($val['sha256']) ? $val['sha256'] : null; $sha256 = isset($val['sha256']) ? $val['sha256'] : null;
if($sha256capable) { if($sha256capable) {
// clean file name
$tempname = uupCleanSha256($name); $tempname = uupCleanSha256($name);
if(isset($files[$tempname])) { if(isset($files[$tempname])) {
// check existing file with the same name
if(preg_match('/\.cab$/i', $tempname)) {
// compare cab files only
if($size > $files[$tempname]['size']) { if($size > $files[$tempname]['size']) {
$smaller = uupAppendSha1($tempname, $files[$tempname]['sha1']); // if the existing file is smaller, rename it
$files[$smaller] = $files[$tempname]; $express = 'baseless_'.$tempname;
$files[$express] = $files[$tempname];
unset($files[$tempname]); unset($files[$tempname]);
$newName = $tempname; $newName = $tempname;
} else { } else {
// if the new file is smaller, rename it
$newName = 'baseless_'.$tempname;
}
} else {
// not a cab file, append hash to differentiate
$newName = uupAppendSha1($tempname, $sha1); $newName = uupAppendSha1($tempname, $sha1);
} }
} else { } else {
@ -580,7 +518,8 @@ function uupAppendSha1($name, $sha1) {
function uupCleanSha256($name) { function uupCleanSha256($name) {
$replace = array( $replace = array(
'prss_signed_appx_' => null, 'MetadataESD_' => null,
'metadataesd_' => null,
'~31bf3856ad364e35' => null, '~31bf3856ad364e35' => null,
'~~.' => '.', '~~.' => '.',
'~.' => '.', '~.' => '.',

View File

@ -1,6 +1,6 @@
<?php <?php
/* /*
Copyright 2022 UUP dump API authors Copyright 2019 UUP dump API authors
Licensed under the Apache License, Version 2.0 (the "License"); Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. you may not use this file except in compliance with the License.
@ -21,7 +21,7 @@ require_once dirname(__FILE__).'/updateinfo.php';
function uupListEditions($lang = 'en-us', $updateId = 0) { function uupListEditions($lang = 'en-us', $updateId = 0) {
if($updateId) { if($updateId) {
$info = uupUpdateInfo($updateId, false, true); $info = uupUpdateInfo($updateId);
} }
if(!$lang) { if(!$lang) {
@ -56,7 +56,6 @@ function uupListEditions($lang = 'en-us', $updateId = 0) {
$editionListFancy = array(); $editionListFancy = array();
foreach(array_keys($genPack[$lang]) as $edition) { foreach(array_keys($genPack[$lang]) as $edition) {
if($edition == 'LXP') continue; if($edition == 'LXP') continue;
if($edition == 'FOD') continue;
if(isset($fancyEditionNames[$edition])) { if(isset($fancyEditionNames[$edition])) {
$fancyName = $fancyEditionNames[$edition]; $fancyName = $fancyEditionNames[$edition];

View File

@ -16,31 +16,22 @@ limitations under the License.
*/ */
require_once dirname(__FILE__).'/shared/main.php'; require_once dirname(__FILE__).'/shared/main.php';
require_once dirname(__FILE__).'/shared/cache.php';
require_once dirname(__FILE__).'/shared/fileinfo.php';
function uupApiPrivateInvalidateFileinfoCache() { function uupListIds($search = null, $sortByDate = 0) {
$cache1 = new UupDumpCache('listid-0', false); uupApiPrintBrand();
$cache2 = new UupDumpCache('listid-1', false);
$cache1->delete(); if(!file_exists('fileinfo')) return array('error' => 'NO_FILEINFO_DIR');
$cache2->delete();
}
function uupApiPrivateGetFromFileinfo($sortByDate = 0) { $files = scandir('fileinfo');
$dirs = uupApiGetFileinfoDirs();
$fileinfo = $dirs['fileinfoData'];
$fileinfoRoot = $dirs['fileinfo'];
$files = scandir($fileinfo);
$files = preg_grep('/\.json$/', $files); $files = preg_grep('/\.json$/', $files);
consoleLogger('Parsing database info...'); consoleLogger('Parsing database info...');
$cacheFile = $fileinfoRoot.'/cache.json'; $cacheFile = 'cache/fileinfo_v2.json';
$cacheV2Version = 1; $cacheV2Version = 1;
$database = uupApiReadJson($cacheFile); $database = @file_get_contents($cacheFile);
$database = json_decode($database, true);
if(isset($database['version'])) { if(isset($database['version'])) {
$version = $database['version']; $version = $database['version'];
@ -59,13 +50,12 @@ function uupApiPrivateGetFromFileinfo($sortByDate = 0) {
$newDb = array(); $newDb = array();
$builds = array(); $builds = array();
foreach($files as $file) { foreach($files as $file) {
if($file == '.' || $file == '..') if($file == '.' || $file == '..') continue;
continue;
$uuid = preg_replace('/\.json$/', '', $file); $uuid = preg_replace('/\.json$/', '', $file);
if(!isset($database[$uuid])) { if(!isset($database[$uuid])) {
$info = uupApiReadFileinfoMeta($uuid); $info = @file_get_contents('fileinfo/'.$file);
$info = json_decode($info, true);
$title = isset($info['title']) ? $info['title'] : 'UNKNOWN'; $title = isset($info['title']) ? $info['title'] : 'UNKNOWN';
$build = isset($info['build']) ? $info['build'] : 'UNKNOWN'; $build = isset($info['build']) ? $info['build'] : 'UNKNOWN';
@ -115,7 +105,12 @@ function uupApiPrivateGetFromFileinfo($sortByDate = 0) {
$builds[$tmp.$arch.$title.$uuid] = $temp; $builds[$tmp.$arch.$title.$uuid] = $temp;
} }
if(empty($buildAssoc)) return []; if(empty($buildAssoc)) {
return array(
'apiVersion' => uupApiVersion(),
'builds' => array(),
);
}
krsort($buildAssoc); krsort($buildAssoc);
$buildsNew = array(); $buildsNew = array();
@ -146,27 +141,7 @@ function uupApiPrivateGetFromFileinfo($sortByDate = 0) {
if(!$success) consoleLogger('Failed to update database cache.'); if(!$success) consoleLogger('Failed to update database cache.');
} }
return $builds; if($search) {
}
function uupListIds($search = null, $sortByDate = 0) {
uupApiPrintBrand();
$sortByDate = $sortByDate ? 1 : 0;
$res = "listid-$sortByDate";
$cache = new UupDumpCache($res, false);
$builds = $cache->get();
$cached = ($builds !== false);
if(!$cached) {
$builds = uupApiPrivateGetFromFileinfo($sortByDate);
if($builds === false) return ['error' => 'NO_FILEINFO_DIR'];
$cache->put($builds, 60);
}
if(count($builds) && $search != null) {
if(!preg_match('/^regex:/', $search)) { if(!preg_match('/^regex:/', $search)) {
$searchSafe = preg_quote($search, '/'); $searchSafe = preg_quote($search, '/');

View File

@ -1,6 +1,6 @@
<?php <?php
/* /*
Copyright 2022 UUP dump API authors Copyright 2019 UUP dump API authors
Licensed under the Apache License, Version 2.0 (the "License"); Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. you may not use this file except in compliance with the License.
@ -21,7 +21,7 @@ require_once dirname(__FILE__).'/updateinfo.php';
function uupListLangs($updateId = 0) { function uupListLangs($updateId = 0) {
if($updateId) { if($updateId) {
$info = uupUpdateInfo($updateId, false, true); $info = uupUpdateInfo($updateId);
} }
if(isset($info['info'])) { if(isset($info['info'])) {
@ -50,9 +50,6 @@ function uupListLangs($updateId = 0) {
if(!count(array_diff(array_keys($val), array('LXP')))) { if(!count(array_diff(array_keys($val), array('LXP')))) {
continue; continue;
} }
if(!count(array_diff(array_keys($val), array('FOD')))) {
continue;
}
if(isset($fancyLangNames[$key])) { if(isset($fancyLangNames[$key])) {
$fancyName = $fancyLangNames[$key]; $fancyName = $fancyLangNames[$key];

View File

@ -10,7 +10,7 @@ Parameters:
- **Supported values:** `amd64`, `x86`, `arm64`, `all` - **Supported values:** `amd64`, `x86`, `arm64`, `all`
- `ring` - Channel to use when fetching information (Previously called Ring) - `ring` - Channel to use when fetching information (Previously called Ring)
- **Supported values:** `Canary`, `Dev`, `Beta`, `ReleasePreview`, `Retail` - **Supported values:** `Dev`, `Beta`, `ReleasePreview`, `Retail`
- **Supported Ring values :** `WIF`, `WIS`, `RP` - **Supported Ring values :** `WIF`, `WIS`, `RP`
- `flight` - Content type to use when fetching information (Previously called Flight) - `flight` - Content type to use when fetching information (Previously called Flight)
@ -82,7 +82,7 @@ Parameters:
- **Supported values:** any update UUID - **Supported values:** any update UUID
#### updateinfo.php: `uupUpdateInfo($updateId, $onlyInfo, $ignoreFiles);` #### updateinfo.php: `uupUpdateInfo($updateId, $onlyInfo);`
Outputs specified information of specified `updateId`. Outputs specified information of specified `updateId`.
Parameters: Parameters:
@ -92,36 +92,12 @@ Parameters:
- `onlyInfo` - Key to output - `onlyInfo` - Key to output
- **Supported values:** any string - **Supported values:** any string
- `ignoreFiles` - Skips the `files` key in the output
- **Supported values:** `true` or `false`
#### shared/main.php: `uupApiVersion();` #### shared/main.php: `uupApiVersion();`
Returns version of the API. Returns version of the API.
Parameters: Parameters:
- None - None
#### shared/utils.php: `uupApiCheckUpdateId($updateId);`
Checks if the provided update ID is correctly formatted.
Parameters:
- `updateId` - update ID to check
- **Supported values:** Any string
#### shared/utils.php: `uupApiIsServer($skuId);`
Checks if the provided SKU ID is a Windows Sever SKU.
Parameters:
- `skuId` - SKU ID to check
- **Supported values:** Any integer
#### shared/utils.php: `uupApiBuildMajor($build);`
Returns a build major of the build number.
Parameters:
- `build` - Build number (for example 22621.1) to split
- **Supported values:** Any correctly formatted build number
### Error codes thrown by API ### Error codes thrown by API
**fetchupd.php** **fetchupd.php**
- UNKNOWN_ARCH - UNKNOWN_ARCH
@ -132,7 +108,6 @@ Parameters:
- ILLEGAL_MINOR - ILLEGAL_MINOR
- NO_UPDATE_FOUND - NO_UPDATE_FOUND
- EMPTY_FILELIST - EMPTY_FILELIST
- WU_REQUEST_FAILED
**get.php** **get.php**
- UNSUPPORTED_LANG - UNSUPPORTED_LANG
@ -143,7 +118,6 @@ Parameters:
- MISSING_FILES - MISSING_FILES
- NO_FILES - NO_FILES
- XML_PARSE_ERROR - XML_PARSE_ERROR
- WU_REQUEST_FAILED
**listeditions.php** **listeditions.php**
- UNSUPPORTED_LANG - UNSUPPORTED_LANG

View File

@ -25,43 +25,19 @@ function uupDevice() {
return base64_encode(chunk_split($data, 1, "\0")); return base64_encode(chunk_split($data, 1, "\0"));
} }
function uupSaveCookieFromResponse($out) {
$outDecoded = html_entity_decode($out);
preg_match('/<NewCookie>.*?<\/NewCookie>|<GetCookieResult>.*?<\/GetCookieResult>/', $outDecoded, $cookieData);
if(empty($cookieData))
return false;
preg_match('/<Expiration>.*<\/Expiration>/', $cookieData[0], $expirationDate);
preg_match('/<EncryptedData>.*<\/EncryptedData>/', $cookieData[0], $encryptedData);
$expirationDate = preg_replace('/<Expiration>|<\/Expiration>/', '', $expirationDate[0]);
$encryptedData = preg_replace('/<EncryptedData>|<\/EncryptedData>/', '', $encryptedData[0]);
$cookieData = array(
'expirationDate' => $expirationDate,
'encryptedData' => $encryptedData,
);
$cookieStorage = new UupDumpCache('WuRequestCookie', false);
$cookieStorage->put($cookieData, false);
return $cookieData;
}
function uupInvalidateCookie() {
$cookieStorage = new UupDumpCache('WuRequestCookie', false);
$cookieInfo = $cookieStorage->delete();
}
function uupEncryptedData() { function uupEncryptedData() {
$cookieStorage = new UupDumpCache('WuRequestCookie', false); $cookieInfo = @file_get_contents(dirname(__FILE__).'/cookie.json');
$cookieInfo = $cookieStorage->get(); $cookieInfo = json_decode($cookieInfo, 1);
if(empty($cookieInfo)) { if(empty($cookieInfo)) {
$data = sendWuPostRequestHelper('client', 'composeGetCookieRequest', [], false); $postData = composeGetCookieRequest(uupDevice());
$cookieInfo = uupSaveCookieFromResponse($data['out']); sendWuPostRequest('https://fe3.delivery.mp.microsoft.com/ClientWebService/client.asmx', $postData);
$encData = uupEncryptedData();
} else {
$encData = $cookieInfo['encryptedData'];
} }
return $cookieInfo['encryptedData']; return $encData;
} }
?>

View File

@ -1,76 +0,0 @@
<?php
/*
Copyright 2022 eraseyourknees
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
class UupDumpCache {
private $cacheFile;
private $newCacheVersion = 1;
public function __construct($resource, private $isCompressed = true) {
$res = $resource."+cache_v".$this->newCacheVersion;
$cacheHash = hash('sha256', strtolower($res));
$ext = $isCompressed ? '.json.gz' : '.json';
$this->cacheFile = 'cache/'.$cacheHash.$ext;
}
public function getFileName() {
return $this->cacheFile;
}
public function delete() {
@unlink($this->cacheFile);
}
public function get() {
$cacheFile = $this->cacheFile;
if(!file_exists($cacheFile)) {
return false;
}
$cache = @file_get_contents($cacheFile);
if($this->isCompressed) $cache = @gzdecode($cache);
$cache = json_decode($cache, 1);
$expires = $cache['expires'];
$isExpired = ($expires !== false) && (time() > $expires);
if(empty($cache['content']) || $isExpired) {
$this->delete();
return false;
}
return $cache['content'];
}
public function put($content, $validity) {
$cacheFile = $this->cacheFile;
$expires = $validity ? time() + $validity : false;
$cache = array(
'expires' => $expires,
'content' => $content,
);
if(!file_exists('cache')) mkdir('cache');
$cacheContent = json_encode($cache)."\n";
if($this->isCompressed) $cacheContent = @gzencode($cacheContent);
@file_put_contents($cacheFile, $cacheContent);
}
}

View File

@ -1,94 +0,0 @@
<?php
/*
Copyright 2022 UUP dump API authors
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
require_once dirname(__FILE__).'/utils.php';
function uupApiGetFileinfoDirs() {
$dirs = [];
$dirs['fileinfo'] = 'fileinfo';
$dirs['fileinfoMeta'] = $dirs['fileinfo'].'/metadata';
$dirs['fileinfoData'] = $dirs['fileinfo'].'/full';
foreach($dirs as $dir) {
if(!file_exists($dir)) mkdir($dir);
}
return $dirs;
}
function uupApiGetFileinfoName($updateId, $meta = false) {
$fileName = $updateId.'.json';
$dirs = uupApiGetFileinfoDirs();
$fileinfoMeta = $dirs['fileinfoMeta'].'/'.$fileName;
$fileinfoData = $dirs['fileinfoData'].'/'.$fileName;
return $meta ? $fileinfoMeta : $fileinfoData;
}
function uupApiFileInfoExists($updateId) {
return file_exists(uupApiGetFileinfoName($updateId));
}
function uupApiWriteFileinfoMeta($updateId, $info) {
if(isset($info['files']))
unset($info['files']);
$file = uupApiGetFileinfoName($updateId, true);
return uupApiWriteJson($file, $info);
}
function uupApiWriteFileinfo($updateId, $info) {
$file = uupApiGetFileinfoName($updateId);
if(uupApiWriteJson($file, $info) === false)
return false;
return uupApiWriteFileinfoMeta($updateId, $info);
}
function uupApiReadFileinfoMeta($updateId) {
$file = uupApiGetFileinfoName($updateId, true);
if(file_exists($file))
return uupApiReadJson($file);
$info = uupApiReadFileinfo($updateId, false);
if($info === false)
return false;
if(isset($info['files']))
unset($info['files']);
if(uupApiWriteFileinfoMeta($updateId, $info) === false)
return false;
return $info;
}
function uupApiReadFileinfo($updateId, $meta = false) {
if(!uupApiFileInfoExists($updateId))
return false;
if($meta === true)
return uupApiReadFileinfoMeta($updateId);
$file = uupApiGetFileinfoName($updateId);
$info = uupApiReadJson($file);
return $info;
}

View File

@ -16,7 +16,7 @@ limitations under the License.
*/ */
function uupApiVersion() { function uupApiVersion() {
return '1.41.0'; return '1.32.0';
} }
require_once dirname(__FILE__).'/auths.php'; require_once dirname(__FILE__).'/auths.php';

View File

@ -1,6 +1,6 @@
<?php <?php
/* /*
Copyright 2022 UUP dump API authors Copyright 2021 UUP dump API authors
Licensed under the Apache License, Version 2.0 (the "License"); Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. you may not use this file except in compliance with the License.
@ -19,7 +19,6 @@ require_once dirname(__FILE__).'/../listid.php';
function uupGetInfoTexts() { function uupGetInfoTexts() {
$fancyLangNames = array( $fancyLangNames = array(
'neutral' => 'Any Language',
'ar-sa' => 'Arabic (Saudi Arabia)', 'ar-sa' => 'Arabic (Saudi Arabia)',
'bg-bg' => 'Bulgarian', 'bg-bg' => 'Bulgarian',
'cs-cz' => 'Czech', 'cs-cz' => 'Czech',
@ -62,9 +61,6 @@ function uupGetInfoTexts() {
); );
$fancyEditionNames = array( $fancyEditionNames = array(
'APP' => 'Microsoft Store Inbox Apps',
'APP_MOMENT' => 'Microsoft Store Moment Apps',
'FOD' => 'Features on Demand (Capabilities)',
'CLOUD' => 'Windows S', 'CLOUD' => 'Windows S',
'CLOUDN' => 'Windows S N', 'CLOUDN' => 'Windows S N',
'CLOUDE' => 'Windows Lean', 'CLOUDE' => 'Windows Lean',
@ -203,12 +199,165 @@ function uupGetInfoTexts() {
} }
function uupGetGenPacks($build = 15063, $arch = null, $updateId = null) { function uupGetGenPacks($build = 15063, $arch = null, $updateId = null) {
if(empty($updateId)) return []; $internalPacks = dirname(__FILE__).'/packs';
if(!file_exists('packs/'.$updateId.'.json.gz')) return [];
if(!file_exists($internalPacks.'/metadata.json')) {
if(!uupCreateInternalPacksMetadata($internalPacks)) {
return array();
}
}
if(!empty($updateId)) {
if(file_exists('packs/'.$updateId.'.json.gz')) {
$genPack = @gzdecode(@file_get_contents('packs/'.$updateId.'.json.gz')); $genPack = @gzdecode(@file_get_contents('packs/'.$updateId.'.json.gz'));
if(empty($genPack)) return []; if(empty($genPack)) return array();
$genPack = json_decode($genPack, 1); $genPack = json_decode($genPack, 1);
return $genPack; return $genPack;
} }
}
$metadata = @file_get_contents($internalPacks.'/metadata.json');
if(empty($metadata)) {
return array();
} else {
$metadata = json_decode($metadata, 1);
}
$hashDetermined = 0;
$useAllHashesForBuild = 0;
if($updateId) {
if(isset($metadata['knownIds'][$updateId])) {
$hash = $metadata['knownIds'][$updateId];
$hashDetermined = 1;
}
}
if(!$hashDetermined) {
foreach($metadata['knownBuilds'] as $buildNum => $val) {
if($build < $buildNum) continue;
$useBuild = $buildNum;
break;
}
if(!isset($useBuild)) {
return array();
}
if(!$arch && !isset($metadata['knownBuilds'][$useBuild][$arch])) {
$genPack = array();
foreach($metadata['knownBuilds'][$useBuild] as $hash) {
$temp = @gzdecode(@file_get_contents($internalPacks.'/'.$hash.'.json.gz'));
if(!empty($temp)) {
$temp = json_decode($temp, 1);
$genPack = array_merge_recursive($genPack, $temp);
unset($temp);
}
}
} elseif(!isset($metadata['knownBuilds'][$useBuild][$arch])) {
return array();
} else {
$hash = $metadata['knownBuilds'][$useBuild][$arch];
}
}
if(!isset($genPack)) {
$genPack = @gzdecode(@file_get_contents($internalPacks.'/'.$hash.'.json.gz'));
if(!empty($genPack)) {
$genPack = json_decode($genPack, 1);
} else {
$genPack = array();
}
}
return $genPack;
}
//Function to regenerate internal packs. Should not be used when not needed.
function uupCreateInternalPacksMetadata($internalPacks) {
$metadataCreationAllowed = 0;
if(!$metadataCreationAllowed) return false;
$builds = uupListIds();
if(isset($ids['error'])) {
return false;
}
$builds = $builds['builds'];
if(!file_exists('packs')) return false;
if(!file_exists($internalPacks)) {
if(!mkdir($internalPacks)) {
return false;
}
} else {
rmdir($internalPacks);
mkdir($internalPacks);
}
$files = scandir('packs');
$files = preg_grep('/\.json.gz$/', $files);
$packs = array();
foreach($builds as $build) {
$uuid = $build['uuid'];
$file = $uuid.'.json.gz';
if(!file_exists('packs/'.$file)) continue;
$genPack = @gzdecode(@file_get_contents('packs/'.$file));
$hash = hash('sha1', $genPack);
if(!file_exists($internalPacks.'/'.$hash.'.json.gz')) {
if(!copy('packs/'.$file, $internalPacks.'/'.$hash.'.json.gz')) {
return false;
}
}
$packs['knownIds'][$uuid] = $hash;
$buildNum = explode('.', $build['build']);
$buildNum = $buildNum[0];
$packs['knownBuilds'][$buildNum][$build['arch']] = $hash;
}
file_put_contents($internalPacks.'/metadata.json', json_encode($packs)."\n");
return true;
}
//Emulation of legacy packs. Do not use in new scripts due to extremely slow process.
function uupGetPacks($build = 15063) {
$returnArray = uupGetInfoTexts();
$genPack = uupGetGenPacks($build);
foreach($genPack as $lang => $editions) {
$packsForLangs[$lang] = array_keys($editions);
$packsForLangs[$lang][] = $lang;
foreach(array_keys($editions) as $edition) {
foreach($editions[$edition] as $name) {
$newName = preg_replace('/^cabs_|^metadataesd_|~31bf3856ad364e35/i', '', $name);
$newName = preg_replace('/~~\.|~\./', '.', $newName);
$newName = preg_replace('/~/', '-', $newName);
$newName = strtolower($newName);
$packs[$lang][$edition][] = $newName;
}
$editionPacks[$edition] = $edition;
$packs[$edition][$edition] = array();
$skipNeutral[$edition] = 1;
$skipLangPack[$edition] = 1;
}
}
$returnArray['packs'] = $packs;
$returnArray['packsForLangs'] = $packsForLangs;
$returnArray['editionPacks'] = $editionPacks;
$returnArray['skipNeutral'] = $skipNeutral;
$returnArray['skipLangPack'] = $skipLangPack;
return $returnArray;
}

Some files were not shown because too many files have changed in this diff Show More