| 1 | // other plugins can use ctx.state.download_counter_ignore to mark downloads that shouldn't be counted |
| 2 | |
| 3 | exports.description = "Counts downloads for each file, and displays the total in the list or file menu" |
| 4 | exports.version = 6.4 // removed legacy code; fixed wrong key for files with % in the name |
| 5 | exports.apiRequired = 8.89 // openDb |
| 6 | |
| 7 | exports.config = { |
| 8 | where: { frontend: true, label: "Where to display counter", type: 'select', defaultValue: 'menu', |
| 9 | options: ['list', { value: 'menu', label: "file menu" }], |
| 10 | }, |
| 11 | archives: { defaultValue: true, type: 'boolean', label: "Count files in zip/archives" }, |
| 12 | } |
| 13 | exports.configDialog = { |
| 14 | sx: { maxWidth: '20em' }, |
| 15 | } |
| 16 | |
| 17 | exports.init = async api => { |
| 18 | const db = await api.openDb('counters.kv', { defaultPutDelay: 5_000, maxPutDelay: 30_000 }) |
| 19 | return { |
| 20 | frontend_js: 'main.js', |
| 21 | frontend_css: 'style.css', |
| 22 | middleware: ctx => () => { // callback = execute after other middlewares are done |
| 23 | if (ctx.status >= 300 || ctx.state.download_counter_ignore || ctx.state.considerAsGui || ctx.state.includesLastByte === false) return |
| 24 | if (!(ctx.state.vfsNode || api.getConfig('archives') && ctx.state.archive)) return |
| 25 | ctx.state.completed.then(() => { |
| 26 | const key = uri2key(ctx.path) |
| 27 | const entries = ctx.state.vfsNode ? [key] |
| 28 | : ctx.state.originalStream?.getArchiveEntries?.().filter(x => x.at(-1) !== '/').map(x => key + path2key(x)) |
| 29 | if (!entries) return |
| 30 | for (const k of entries) |
| 31 | db.put(k, db.getSync(k) + 1 || 1) |
| 32 | }) |
| 33 | }, |
| 34 | onDirEntry({ entry, listUri }) { |
| 35 | const k = uri2key(listUri) + path2key(entry.n) |
| 36 | const n = db.getSync(k) |
| 37 | if (n) |
| 38 | entry.hits = n |
| 39 | } |
| 40 | } |
| 41 | |
| 42 | function uri2key(uri) { // normalize uri to avoid having different keys for the same file |
| 43 | return path2key(api.misc.pathDecode(uri)) |
| 44 | } |
| 45 | |
| 46 | function path2key(path) { |
| 47 | return path.toLowerCase() |
| 48 | } |
| 49 | } |