mirror of
https://github.com/dscalzi/HeliosLauncher.git
synced 2024-12-22 11:42:14 -08:00
Working on experimental features, optimizing downloads.
This commit is contained in:
parent
8173f85df0
commit
f5702f62a6
@ -22,6 +22,7 @@
|
|||||||
* *
|
* *
|
||||||
******************************************************************************/
|
******************************************************************************/
|
||||||
|
|
||||||
|
/* Reset body, html, and div presets. */
|
||||||
body, html, div {
|
body, html, div {
|
||||||
margin: 0px;
|
margin: 0px;
|
||||||
padding: 0px;
|
padding: 0px;
|
||||||
@ -38,7 +39,7 @@ html {
|
|||||||
* *
|
* *
|
||||||
******************************************************************************/
|
******************************************************************************/
|
||||||
|
|
||||||
/* Main div header container/ */
|
/* Main div header container. */
|
||||||
#header_container {
|
#header_container {
|
||||||
background-color: black;
|
background-color: black;
|
||||||
padding: 5px;
|
padding: 5px;
|
||||||
@ -68,19 +69,53 @@ html {
|
|||||||
display: block;
|
display: block;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Div container for the social buttons */
|
/* Div container for the social buttons. */
|
||||||
#header_social_container {
|
#header_social_container {
|
||||||
font-size: 16px;
|
|
||||||
position: absolute;
|
position: absolute;
|
||||||
bottom: 0px;
|
bottom: 0px;
|
||||||
right: 0px;
|
right: 0px;
|
||||||
margin-right: 5px;
|
margin-bottom: 5px;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Social buttons */
|
/* Social buttons. */
|
||||||
.header_social_img {
|
.header_social_img {
|
||||||
height: 25px;
|
height: 25px;
|
||||||
width: auto;
|
width: auto;
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
margin-right: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
* *
|
||||||
|
* Left Body Container *
|
||||||
|
* *
|
||||||
|
******************************************************************************/
|
||||||
|
|
||||||
|
#body_left_container {
|
||||||
|
width: 25%;
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
* *
|
||||||
|
* Right Body Container *
|
||||||
|
* *
|
||||||
|
******************************************************************************/
|
||||||
|
|
||||||
|
#body_right_container {
|
||||||
|
width: 75%;
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mtoggle_button {
|
||||||
|
text-align:centre;
|
||||||
|
margin:5px 2px;
|
||||||
|
padding:0.4em 3em;
|
||||||
|
color:#000;
|
||||||
|
background-color:#FFF;
|
||||||
|
border-radius:10px;
|
||||||
|
display:inline-block;
|
||||||
|
border:solid 1px #CCC;
|
||||||
|
cursor:pointer;
|
||||||
}
|
}
|
@ -4,7 +4,8 @@ const path = require('path')
|
|||||||
const mkpath = require('mkdirp');
|
const mkpath = require('mkdirp');
|
||||||
const async = require('async')
|
const async = require('async')
|
||||||
const crypto = require('crypto')
|
const crypto = require('crypto')
|
||||||
const libary = require('./library.js')
|
const library = require('./library.js')
|
||||||
|
const {BrowserWindow} = require('electron')
|
||||||
|
|
||||||
function Asset(from, to, size, hash){
|
function Asset(from, to, size, hash){
|
||||||
this.from = from
|
this.from = from
|
||||||
@ -21,11 +22,19 @@ function AssetIndex(id, sha1, size, url, totalSize){
|
|||||||
this.totalSize = totalSize
|
this.totalSize = totalSize
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function Library(id, sha1, size, from, to){
|
||||||
|
this.id = id
|
||||||
|
this.sha1 = sha1
|
||||||
|
this.size = size
|
||||||
|
this.from = from
|
||||||
|
this.to = to
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This function will download the version index data and read it into a Javascript
|
* This function will download the version index data and read it into a Javascript
|
||||||
* Object. This object will then be returned.
|
* Object. This object will then be returned.
|
||||||
*/
|
*/
|
||||||
exports.parseVersionData = function(version, basePath){
|
parseVersionData = function(version, basePath){
|
||||||
const name = version + '.json'
|
const name = version + '.json'
|
||||||
const baseURL = 'https://s3.amazonaws.com/Minecraft.Download/versions/' + version + '/' + name
|
const baseURL = 'https://s3.amazonaws.com/Minecraft.Download/versions/' + version + '/' + name
|
||||||
const versionPath = path.join(basePath, 'versions', version)
|
const versionPath = path.join(basePath, 'versions', version)
|
||||||
@ -46,7 +55,7 @@ exports.parseVersionData = function(version, basePath){
|
|||||||
* Download the client for version. This file is 'client.jar' although
|
* Download the client for version. This file is 'client.jar' although
|
||||||
* it must be renamed to '{version}'.jar.
|
* it must be renamed to '{version}'.jar.
|
||||||
*/
|
*/
|
||||||
exports.downloadClient = function(versionData, basePath){
|
downloadClient = function(versionData, basePath){
|
||||||
const dls = versionData['downloads']
|
const dls = versionData['downloads']
|
||||||
const clientData = dls['client']
|
const clientData = dls['client']
|
||||||
const url = clientData['url']
|
const url = clientData['url']
|
||||||
@ -68,7 +77,7 @@ exports.downloadClient = function(versionData, basePath){
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
exports.downloadLogConfig = function(versionData, basePath){
|
downloadLogConfig = function(versionData, basePath){
|
||||||
const logging = versionData['logging']
|
const logging = versionData['logging']
|
||||||
const client = logging['client']
|
const client = logging['client']
|
||||||
const file = client['file']
|
const file = client['file']
|
||||||
@ -90,73 +99,53 @@ exports.downloadLogConfig = function(versionData, basePath){
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
exports.downloadLibraries = function(versionData, basePath){
|
downloadLibraries = function(versionData, basePath){
|
||||||
const libArr = versionData['libraries']
|
const libArr = versionData['libraries']
|
||||||
const libPath = path.join(basePath, 'libraries')
|
const libPath = path.join(basePath, 'libraries')
|
||||||
async.eachLimit(libArr, 1, function(lib, cb){
|
|
||||||
if(library.validateRules(lib['rules'])){
|
let win = BrowserWindow.getFocusedWindow()
|
||||||
if(lib['natives'] == null){
|
const libDlQueue = []
|
||||||
const dlInfo = lib['downloads']
|
let dlSize = 0
|
||||||
const artifact = dlInfo['artifact']
|
|
||||||
const sha1 = artifact['sha1']
|
//Check validity of each library. If the hashs don't match, download the library.
|
||||||
const libSize = artifact['size']
|
libArr.forEach(function(lib, index){
|
||||||
const to = path.join(libPath, artifact['path'])
|
if(library.validateRules(lib.rules)){
|
||||||
const from = artifact['url']
|
let artifact = null
|
||||||
if(!validateLocalIntegrity(to, 'sha1', sha1)){
|
if(lib.natives == null){
|
||||||
mkpath.sync(path.join(to, ".."))
|
artifact = lib.downloads.artifact
|
||||||
let req = request(from)
|
} else {
|
||||||
let writeStream = fs.createWriteStream(to)
|
artifact = lib.downloads.classifiers[lib.natives[library.mojangFriendlyOS()]]
|
||||||
req.pipe(writeStream)
|
}
|
||||||
|
const libItm = new Library(lib.name, artifact.sha1, artifact.size, artifact.url, path.join(libPath, artifact.path))
|
||||||
|
if(!validateLocalIntegrity(libItm.to, 'sha1', libItm.sha1)){
|
||||||
|
dlSize += libItm.size
|
||||||
|
libDlQueue.push(libItm)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
let acc = 0;
|
let acc = 0;
|
||||||
|
|
||||||
|
//Download all libraries that failed validation.
|
||||||
|
async.eachLimit(libDlQueue, 1, function(lib, cb){
|
||||||
|
mkpath.sync(path.join(lib.to, '..'))
|
||||||
|
let req = request(lib.from)
|
||||||
|
let writeStream = fs.createWriteStream(lib.to)
|
||||||
|
req.pipe(writeStream)
|
||||||
|
|
||||||
req.on('data', function(chunk){
|
req.on('data', function(chunk){
|
||||||
acc += chunk.length
|
acc += chunk.length
|
||||||
//console.log('Progress', acc/libSize)
|
//console.log('Progress', acc/dlSize)
|
||||||
|
win.setProgressBar(acc/dlSize)
|
||||||
})
|
})
|
||||||
writeStream.on('close', function(){
|
writeStream.on('close', cb)
|
||||||
cb()
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
cb()
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
const natives = lib['natives']
|
|
||||||
const opSys = library.mojangFriendlyOS()
|
|
||||||
const indexId = natives[opSys]
|
|
||||||
const dlInfo = lib['downloads']
|
|
||||||
const classifiers = dlInfo['classifiers']
|
|
||||||
const artifact = classifiers[indexId]
|
|
||||||
|
|
||||||
const libSize = artifact['size']
|
|
||||||
const to = path.join(libPath, artifact['path'])
|
|
||||||
const from = artifact['url']
|
|
||||||
const sha1 = artifact['sha1']
|
|
||||||
|
|
||||||
if(!validateLocalIntegrity(to, 'sha1', sha1)){
|
|
||||||
mkpath.sync(path.join(to, ".."))
|
|
||||||
let req = request(from)
|
|
||||||
let writeStream = fs.createWriteStream(to)
|
|
||||||
req.pipe(writeStream)
|
|
||||||
let acc = 0;
|
|
||||||
req.on('data', function(chunk){
|
|
||||||
acc += chunk.length
|
|
||||||
console.log('Progress', acc/libSize)
|
|
||||||
})
|
|
||||||
writeStream.on('close', function(){
|
|
||||||
cb()
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
cb()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
cb()
|
|
||||||
}
|
|
||||||
}, function(err){
|
}, function(err){
|
||||||
if(err){
|
if(err){
|
||||||
console.log('A library failed to process');
|
console.log('A library failed to process');
|
||||||
} else {
|
} else {
|
||||||
console.log('All libraries have been processed successfully');
|
console.log('All libraries have been processed successfully');
|
||||||
}
|
}
|
||||||
|
win.setProgressBar(-1)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -164,13 +153,12 @@ exports.downloadLibraries = function(versionData, basePath){
|
|||||||
* Given an index url, this function will asynchonously download the
|
* Given an index url, this function will asynchonously download the
|
||||||
* assets associated with that version.
|
* assets associated with that version.
|
||||||
*/
|
*/
|
||||||
exports.downloadAssets = function(versionData, basePath){
|
downloadAssets = function(versionData, basePath){
|
||||||
//Asset index constants.
|
//Asset index constants.
|
||||||
const assetIndex = versionData['assetIndex']
|
const assetIndex = versionData.assetIndex
|
||||||
const indexURL = assetIndex['url']
|
const indexURL = assetIndex.url
|
||||||
const datasize = assetIndex['totalSize']
|
const gameVersion = versionData.id
|
||||||
const gameVersion = versionData['id']
|
const assetVersion = assetIndex.id
|
||||||
const assetVersion = assetIndex['id']
|
|
||||||
const name = assetVersion + '.json'
|
const name = assetVersion + '.json'
|
||||||
|
|
||||||
//Asset constants
|
//Asset constants
|
||||||
@ -179,45 +167,50 @@ exports.downloadAssets = function(versionData, basePath){
|
|||||||
const indexPath = path.join(localPath, 'indexes')
|
const indexPath = path.join(localPath, 'indexes')
|
||||||
const objectPath = path.join(localPath, 'objects')
|
const objectPath = path.join(localPath, 'objects')
|
||||||
|
|
||||||
request.head(indexURL, function (err, res, body) {
|
let win = BrowserWindow.getFocusedWindow()
|
||||||
|
|
||||||
|
const assetIndexLoc = path.join(indexPath, name)
|
||||||
|
/*if(!fs.existsSync(assetIndexLoc)){
|
||||||
|
|
||||||
|
}*/
|
||||||
console.log('Downloading ' + gameVersion + ' asset index.')
|
console.log('Downloading ' + gameVersion + ' asset index.')
|
||||||
mkpath.sync(indexPath)
|
mkpath.sync(indexPath)
|
||||||
const stream = request(indexURL).pipe(fs.createWriteStream(path.join(indexPath, name)))
|
const stream = request(indexURL).pipe(fs.createWriteStream(assetIndexLoc))
|
||||||
stream.on('finish', function() {
|
stream.on('finish', function() {
|
||||||
const data = JSON.parse(fs.readFileSync(path.join(indexPath, name), 'utf-8'))
|
const data = JSON.parse(fs.readFileSync(assetIndexLoc, 'utf-8'))
|
||||||
const assetArr = []
|
const assetDlQueue = []
|
||||||
Object.keys(data['objects']).forEach(function(key, index){
|
let dlSize = 0;
|
||||||
const ob = data['objects'][key]
|
Object.keys(data.objects).forEach(function(key, index){
|
||||||
const hash = String(ob['hash'])
|
const ob = data.objects[key]
|
||||||
|
const hash = ob.hash
|
||||||
const assetName = path.join(hash.substring(0, 2), hash)
|
const assetName = path.join(hash.substring(0, 2), hash)
|
||||||
const urlName = hash.substring(0, 2) + "/" + hash
|
const urlName = hash.substring(0, 2) + "/" + hash
|
||||||
const ast = new Asset(resourceURL + urlName, path.join(objectPath, assetName), ob['size'], hash)
|
const ast = new Asset(resourceURL + urlName, path.join(objectPath, assetName), ob.size, String(ob.hash))
|
||||||
assetArr.push(ast)
|
if(!validateLocalIntegrity(ast.to, 'sha1', ast.hash)){
|
||||||
|
dlSize += ast.size
|
||||||
|
assetDlQueue.push(ast)
|
||||||
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
let acc = 0;
|
let acc = 0;
|
||||||
async.eachLimit(assetArr, 5, function(asset, cb){
|
async.eachLimit(assetDlQueue, 5, function(asset, cb){
|
||||||
mkpath.sync(path.join(asset.to, ".."))
|
mkpath.sync(path.join(asset.to, ".."))
|
||||||
if(!validateLocalIntegrity(asset.to, 'sha1', asset.hash)){
|
|
||||||
let req = request(asset.from)
|
let req = request(asset.from)
|
||||||
let writeStream = fs.createWriteStream(asset.to)
|
let writeStream = fs.createWriteStream(asset.to)
|
||||||
req.pipe(writeStream)
|
req.pipe(writeStream)
|
||||||
req.on('data', function(chunk){
|
req.on('data', function(chunk){
|
||||||
acc += chunk.length
|
acc += chunk.length
|
||||||
//console.log('Progress', acc/datasize)
|
console.log('Progress', acc/dlSize)
|
||||||
|
win.setProgressBar(acc/dlSize)
|
||||||
})
|
})
|
||||||
writeStream.on('close', function(){
|
writeStream.on('close', cb)
|
||||||
cb()
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
cb()
|
|
||||||
}
|
|
||||||
}, function(err){
|
}, function(err){
|
||||||
if(err){
|
if(err){
|
||||||
console.log('An asset failed to process');
|
console.log('An asset failed to process');
|
||||||
} else {
|
} else {
|
||||||
console.log('All assets have been processed successfully');
|
console.log('All assets have been processed successfully');
|
||||||
}
|
}
|
||||||
})
|
win.setProgressBar(-1)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -240,3 +233,11 @@ validateLocalIntegrity = function(filePath, algo, hash){
|
|||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
parseVersionData,
|
||||||
|
downloadClient,
|
||||||
|
downloadLogConfig,
|
||||||
|
downloadLibraries,
|
||||||
|
downloadAssets
|
||||||
|
}
|
44
app/assets/js/windowutils.js
Normal file
44
app/assets/js/windowutils.js
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
const app = require('electron')
|
||||||
|
const remote = require('electron').BrowserWindow
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Doesn't work yet.
|
||||||
|
*/
|
||||||
|
exports.setIconBadge = function(text){
|
||||||
|
if(process.platform === 'darwin'){
|
||||||
|
app.dock.setBadge('' + text)
|
||||||
|
} else if (process.platform === 'win32'){
|
||||||
|
const win = remote.getFocusedWindow()
|
||||||
|
if(text === ''){
|
||||||
|
win.setOverlayIcon(null, '')
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Create badge
|
||||||
|
const canvas = document.createElement('canvas')
|
||||||
|
canvas.height = 140;
|
||||||
|
canvas.width = 140;
|
||||||
|
const ctx = canvas.getContext('2d')
|
||||||
|
ctx.fillStyle = '#a02d2a'
|
||||||
|
ctx.beginPath()
|
||||||
|
ctx.ellipse(70, 70, 70, 70, 0, 0, 2 * Math.PI)
|
||||||
|
ctx.fill()
|
||||||
|
ctx.textAlign = 'center'
|
||||||
|
ctx.fillStyle = 'white'
|
||||||
|
|
||||||
|
if(text.length > 2 ){
|
||||||
|
ctx.font = '75px sans-serif'
|
||||||
|
ctx.fillText('' + text, 70, 98)
|
||||||
|
} else if (text.length > 1){
|
||||||
|
ctx.font = '100px sans-serif'
|
||||||
|
ctx.fillText('' + text, 70, 105)
|
||||||
|
} else {
|
||||||
|
ctx.font = '125px sans-serif'
|
||||||
|
ctx.fillText('' + text, 70, 112)
|
||||||
|
}
|
||||||
|
|
||||||
|
const badgeDataURL = canvas.toDataURL()
|
||||||
|
const img = NativeImage.createFromDataURL(badgeDataURL)
|
||||||
|
win.setOverlayIcon(img, '' + text)
|
||||||
|
}
|
||||||
|
}
|
@ -27,5 +27,18 @@
|
|||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div id="body_left_container">
|
||||||
|
|
||||||
|
</div>
|
||||||
|
<div id="body_right_container">
|
||||||
|
<div id="main_toggle_group">
|
||||||
|
<div><label><input type="radio" name="main_group" class="mtoggle_button"/>News</label></div>
|
||||||
|
<div><label><input type="radio" name="main_group" class="mtoggle_button"/>Map</label></div>
|
||||||
|
<div><label><input type="radio" name="main_group" class="mtoggle_button"/>Mods</label></div>
|
||||||
|
<div><label><input type="radio" name="main_group" class="mtoggle_button"/>FAQ</label></div>
|
||||||
|
<div><label><input type="radio" name="main_group" class="mtoggle_button"/>Log</label></div>
|
||||||
|
<div><label><input type="radio" name="main_group" class="mtoggle_button"/>Settings</label></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
3
index.js
3
index.js
@ -22,11 +22,12 @@ function createWindow() {
|
|||||||
const basePath = path.join(__dirname, 'mcfiles')
|
const basePath = path.join(__dirname, 'mcfiles')
|
||||||
const dataPromise = assetdl.parseVersionData('1.11.2', basePath)
|
const dataPromise = assetdl.parseVersionData('1.11.2', basePath)
|
||||||
dataPromise.then(function(data){
|
dataPromise.then(function(data){
|
||||||
|
assetdl.downloadAssets(data, basePath)
|
||||||
//assetdl.downloadAssets(data, basePath)
|
//assetdl.downloadAssets(data, basePath)
|
||||||
//assetdl.downloadClient(data, basePath)
|
//assetdl.downloadClient(data, basePath)
|
||||||
//assetdl.downloadLogConfig(data, basePath)
|
//assetdl.downloadLogConfig(data, basePath)
|
||||||
//assetdl.downloadLibraries(data, basePath)
|
//assetdl.downloadLibraries(data, basePath)
|
||||||
require('./app/assets/js/launchprocess.js').launchMinecraft(data, basePath)
|
//require('./app/assets/js/launchprocess.js').launchMinecraft(data, basePath)
|
||||||
})*/
|
})*/
|
||||||
|
|
||||||
win.on('closed', () => {
|
win.on('closed', () => {
|
||||||
|
Loading…
Reference in New Issue
Block a user