gd-utils/src/summary.js

127 lines
4.4 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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 }) {
const head = ['類型', '數量', '大小']
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('')
let tail = ['合計', file_count + folder_count, total_size]
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 => {
if (v.ext === '資料夾') v.ext = '[Folder]'
if (v.ext === '無副檔名') v.ext = '[NoExt]'
})
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)
}
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 })
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]
}