Merge pull request #201 from Dahlgren/feature/mods-metadata

Add metadata about mods
This commit is contained in:
Björn Dahlgren 2021-12-28 03:18:08 +01:00 committed by GitHub
commit a2e98d7b1b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 234 additions and 46 deletions

View File

@ -1,43 +0,0 @@
var events = require('events')
var fs = require('fs.extra')
var glob = require('glob')
var path = require('path')
var Mods = function (config) {
this.config = config
this.mods = []
}
Mods.prototype = new events.EventEmitter()
Mods.prototype.delete = function (mod, cb) {
var self = this
fs.rmrf(path.join(this.config.path, mod), function (err) {
cb(err)
if (!err) {
self.updateMods()
}
})
}
Mods.prototype.updateMods = function () {
var self = this
glob('**/{@*,csla,gm,vn,ws}/addons', { cwd: self.config.path }, function (err, files) {
if (err) {
console.log(err)
} else {
var mods = files.map(function (file) {
return {
// Find actual parent mod folder from addons folder
name: path.join(file, '..')
}
})
self.mods = mods
self.emit('mods', mods)
}
})
}
module.exports = Mods

26
lib/mods/folderSize.js Normal file
View File

@ -0,0 +1,26 @@
var async = require('async')
var fs = require('fs')
var glob = require('glob')
var path = require('path')
module.exports = function (modPath, config, callback) {
var basePath = path.resolve(config.path, modPath)
var total = 0
glob('**/*', { cwd: basePath, dot: true }, function (err, files) {
if (err) {
return callback(err, 0)
}
async.forEach(files, function (file, cb) {
fs.stat(path.join(basePath, file), function stat (err, stats) {
if (!err && (stats.isFile() || stats.isSymbolicLink())) {
var size = stats.size || 0
total += size
}
cb()
})
}, function (err) {
callback(err, total)
})
})
}

82
lib/mods/index.js Normal file
View File

@ -0,0 +1,82 @@
var async = require('async')
var events = require('events')
var filesize = require('filesize')
var fs = require('fs.extra')
var glob = require('glob')
var path = require('path')
var folderSize = require('./folderSize')
var modFile = require('./modFile')
var steamMeta = require('./steamMeta')
var Mods = function (config) {
this.config = config
this.mods = []
}
Mods.prototype = new events.EventEmitter()
Mods.prototype.delete = function (mod, cb) {
var self = this
fs.rmrf(path.join(this.config.path, mod), function (err) {
cb(err)
if (!err) {
self.updateMods()
}
})
}
Mods.prototype.updateMods = function () {
var self = this
glob('**/{@*,csla,gm,vn}/addons', { cwd: self.config.path }, function (err, files) {
if (err) {
console.log(err)
return
}
var mods = files.map(function (file) {
// Find actual parent mod folder from addons folder
return path.join(file, '..')
})
async.map(mods, self.resolveModData.bind(self), function (err, mods) {
if (err) {
console.log(err)
return
}
self.mods = mods
self.emit('mods', mods)
})
})
}
Mods.prototype.resolveModData = function (modPath, cb) {
var self = this
async.parallel({
folderSize: function (cb) {
folderSize(modPath, self.config, cb)
},
modFile: function (cb) {
modFile(modPath, self.config, cb)
},
steamMeta: function (cb) {
steamMeta(modPath, self.config, cb)
}
}, function (err, results) {
if (err) {
return cb(err)
}
cb(null, {
name: modPath,
size: results.folderSize,
formattedSize: filesize(results.folderSize),
modFile: results.modFile,
steamMeta: results.steamMeta
})
})
}
module.exports = Mods

30
lib/mods/modFile.js Normal file
View File

@ -0,0 +1,30 @@
var armaClassParser = require('arma-class-parser')
var fs = require('fs')
var path = require('path')
function stripBOM (data) {
if (data.charCodeAt(0) === 0xFEFF) {
return data.slice(1)
}
return data
}
module.exports = function (modPath, config, callback) {
var modCpp = path.resolve(config.path, modPath, 'mod.cpp')
fs.readFile(modCpp, 'utf8', function (err, data) {
if (err) {
return callback(null, null)
}
try {
var meta = armaClassParser.parse(stripBOM(data))
callback(null, {
name: meta.name
})
} catch (err) {
console.log('Error parsing mod.cpp for ' + modPath + ', ' + err)
callback(null, null)
}
})
}

23
lib/mods/steamMeta.js Normal file
View File

@ -0,0 +1,23 @@
var armaClassParser = require('arma-class-parser')
var fs = require('fs')
var path = require('path')
module.exports = function (modPath, config, callback) {
var metaCpp = path.resolve(config.path, modPath, 'meta.cpp')
fs.readFile(metaCpp, 'utf8', function (err, data) {
if (err) {
return callback(null, null)
}
try {
var meta = armaClassParser.parse(data)
callback(null, {
id: meta.publishedid,
name: meta.name
})
} catch (err) {
console.log('Error parsing meta.cpp for ' + modPath + ', ' + err)
callback(null, null)
}
})
}

View File

@ -17,6 +17,7 @@
] ]
}, },
"dependencies": { "dependencies": {
"arma-class-parser": "^1.1.1",
"arma-server": "0.0.10", "arma-server": "0.0.10",
"async": "^0.9.0", "async": "^0.9.0",
"backbone": "1.3.3", "backbone": "1.3.3",

View File

@ -14,6 +14,33 @@ module.exports = Marionette.ItemView.extend({
'click .destroy': 'deleteMod' 'click .destroy': 'deleteMod'
}, },
templateHelpers: function () {
var modFile = this.model.get('modFile')
var steamMeta = this.model.get('steamMeta')
var link = null
var title = null
if (steamMeta && steamMeta.id) {
if (steamMeta.id) {
link = 'https://steamcommunity.com/sharedfiles/filedetails/?id=' + steamMeta.id
}
if (steamMeta.name) {
title = steamMeta.name
}
}
if (modFile && modFile.name) {
title = modFile.name
}
return {
link: link,
title: title
}
},
deleteMod: function (event) { deleteMod: function (event) {
var self = this var self = this
sweetAlert({ sweetAlert({

View File

@ -10,8 +10,32 @@ module.exports = ModListItemView.extend({
template: template, template: template,
templateHelpers: function () { templateHelpers: function () {
var modFile = this.model.get('modFile')
var name = this.model.get('name')
var steamMeta = this.model.get('steamMeta')
var enabled = this.options.server.get('mods').indexOf(name) > -1
var link = null
var title = null
if (steamMeta && steamMeta.id) {
if (steamMeta.id) {
link = 'https://steamcommunity.com/sharedfiles/filedetails/?id=' + steamMeta.id
}
if (steamMeta.name) {
title = steamMeta.name
}
}
if (modFile && modFile.name) {
title = modFile.name
}
return { return {
enabled: this.options.server.get('mods').indexOf(this.model.get('name')) > -1 enabled: enabled,
link: link,
title: title
} }
} }
}) })

View File

@ -6,7 +6,8 @@
<table class="table table-striped"> <table class="table table-striped">
<thead> <thead>
<tr> <tr>
<th>Mod</th> <th width="100%">Mod</th>
<th>Size</th>
<th></th> <th></th>
</tr> </tr>
</thead> </thead>

View File

@ -1,5 +1,15 @@
<td> <td>
<a href='#mods/<%-name%>'><%-name%></a> <%-name%>
<% if (link) { %>
<a href='<%-link%>' target=_blank rel='noopener noreferrer'>
<%-title%>
</a>
<% } else if (title) { %>
<%-title%>
<% } %>
</td>
<td style="text-align: right; white-space: nowrap;">
<%-formattedSize%>
</td> </td>
<td> <td>
<a class="btn btn-danger btn-xs destroy ladda-button pull-right" data-style="expand-left"> <a class="btn btn-danger btn-xs destroy ladda-button pull-right" data-style="expand-left">

View File

@ -3,6 +3,13 @@
<label> <label>
<input type="checkbox" value="<%-name%>" <% if (enabled) { %>checked<% } %> > <input type="checkbox" value="<%-name%>" <% if (enabled) { %>checked<% } %> >
<%-name%> <%-name%>
<% if (link) { %>
<a href='<%-link%>' target=_blank rel='noopener noreferrer'>
<%-title%>
</a>
<% } else if (title) { %>
<%-title%>
<% } %>
</label> </label>
</div> </div>
</td> </td>