gd-utils/src/summary.js

127 lines
4.4 KiB
JavaScript
Raw Normal View History

2020-06-27 14:19:43 +08:00
const Table = require('cli-table3')
const colors = require('colors/safe')
const { escape } = require('html-escaper')
module.exports = { make_table, summary, make_html, make_tg_table }
function make_html ({ file_count, folder_count, total_size, details }) {
2020-07-04 01:41:35 +08:00
const head = ['類型', '數量', '大小']
2020-06-27 14:19:43 +08:00
const th = '<tr>' + head.map(k => `<th>${k}</th>`).join('') + '</tr>'
const td = details.map(v => '<tr>' + [escape(v.ext), v.count, v.size].map(k => `<td>${k}</td>`).join('') + '</tr>').join('')
2020-07-04 01:41:35 +08:00
let tail = ['合計', file_count + folder_count, total_size]
2020-06-27 14:19:43 +08:00
tail = '<tr style="font-weight:bold">' + tail.map(k => `<td>${k}</td>`).join('') + '</tr>'
const table = `<table border="1" cellpadding="12" style="border-collapse:collapse;font-family:serif;font-size:22px;margin:10px auto;text-align: center">
${th}
${td}
${tail}
</table>`
return table
}
function make_table ({ file_count, folder_count, total_size, details }) {
const tb = new Table()
const hAlign = 'center'
const headers = ['Type', 'Count', 'Size'].map(v => ({ content: colors.bold.brightBlue(v), hAlign }))
const records = details.map(v => [v.ext, v.count, v.size]).map(arr => {
return arr.map(content => ({ content, hAlign }))
})
const total_count = file_count + folder_count
const tails = ['总计', total_count, total_size].map(v => ({ content: colors.bold(v), hAlign }))
tb.push(headers, ...records)
tb.push(tails)
return tb.toString() + '\n'
}
function make_tg_table ({ file_count, folder_count, total_size, details }) {
const tb = new Table({
// chars: {
// 'top': '═',
// 'top-mid': '╤',
// 'top-left': '╔',
// 'top-right': '╗',
// 'bottom': '═',
// 'bottom-mid': '╧',
// 'bottom-left': '╚',
// 'bottom-right': '╝',
// 'left': '║',
// 'left-mid': '╟',
// 'right': '║',
// 'right-mid': '╢'
// },
style: {
head: [],
border: []
}
})
const hAlign = 'center'
const headers = ['Type', 'Count', 'Size'].map(v => ({ content: v, hAlign }))
details.forEach(v => {
2020-07-04 01:41:35 +08:00
if (v.ext === '資料夾') v.ext = '[Folder]'
if (v.ext === '無副檔名') v.ext = '[NoExt]'
2020-06-27 14:19:43 +08:00
})
const records = details.map(v => [v.ext, v.count, v.size]).map(arr => arr.map(content => ({ content, hAlign })))
const total_count = file_count + folder_count
const tails = ['Total', total_count, total_size].map(v => ({ content: v, hAlign }))
tb.push(headers, ...records)
tb.push(tails)
return tb.toString().replace(/─/g, '—') // 防止在手机端表格换行 去掉replace后在pc端更美观
}
function summary (info, sort_by) {
const files = info.filter(v => v.mimeType !== 'application/vnd.google-apps.folder')
const file_count = files.length
const folder_count = info.filter(v => v.mimeType === 'application/vnd.google-apps.folder').length
let total_size = info.map(v => Number(v.size) || 0).reduce((acc, val) => acc + val, 0)
total_size = format_size(total_size)
const exts = {}
const sizes = {}
let no_ext = 0; let no_ext_size = 0
files.forEach(v => {
let { name, size } = v
size = Number(size) || 0
const ext = name.split('.').pop().toLowerCase()
if (!name.includes('.') || ext.length > 10) { // 若 . 后超过10字符判断为无扩展名
no_ext_size += size
return no_ext++
}
if (exts[ext]) {
exts[ext]++
} else {
exts[ext] = 1
}
if (sizes[ext]) {
sizes[ext] += size
} else {
sizes[ext] = size
}
})
const details = Object.keys(exts).map(ext => {
const count = exts[ext]
const size = sizes[ext]
return { ext, count, size: format_size(size), raw_size: size }
})
if (sort_by === 'size') {
details.sort((a, b) => b.raw_size - a.raw_size)
} else if (sort_by === 'name') {
details.sort((a, b) => (a.ext > b.ext) ? 1 : -1)
} else {
details.sort((a, b) => b.count - a.count)
}
2020-07-04 01:41:35 +08:00
if (no_ext) details.push({ ext: '無副檔名', count: no_ext, size: format_size(no_ext_size), raw_size: no_ext_size })
if (folder_count) details.push({ ext: '資料夾', count: folder_count, size: 0, raw_size: 0 })
2020-06-27 14:19:43 +08:00
return { file_count, folder_count, total_size, details }
}
function format_size (n) {
n = Number(n)
if (Number.isNaN(n)) return ''
if (n < 0) return 'invalid size'
const units = ['B', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB']
let flag = 0
while (n >= 1024) {
n = (n / 1024)
flag++
}
return n.toFixed(2) + ' ' + units[flag]
}