๐Ÿ“ฆ navidrome / insight-charts

๐Ÿ“„ main.ts ยท 92 lines
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92import { DatabaseSync } from 'node:sqlite'
import { exit } from 'node:process'
import { parseArgs } from 'jsr:@std/cli/parse-args'
import {
  dataFsPie,
  musicFsPie,
  numInstanceLine,
  osPie,
  playerTypePie,
} from './generators.ts'

const flags = parseArgs(Deno.args, {
  string: ['db-path', 'output-dir'],
  boolean: ['help', 'verbose'],
  default: {
    'db-path': Deno.env.get('INSIGHT_DB_PATH'),
    'output-dir': Deno.env.get('INSIGHT_OUTPUT_DIR') ?? '.',
    'verbose': ["1", "true", "yes"].includes(
        (Deno.env.get("INSIGHT_VERBOSE") ?? "").toLowerCase()),
    },
  alias: { d: 'db-path', o: 'output-dir', v: 'verbose' },
})

const log = flags['verbose']
  ? (...args: unknown[]) => {
    const now = new Date()
    const timestamp = now.toISOString()
      .replace(/T/, ' ')
      .replace(/\..+/, '')
      .replace(/-/g, '/')
    console.log(`${timestamp}`, ...args)
  }
  : console.log

flags['output-dir'] = flags['output-dir'].replace(/\/$/, '')

const printUsage = () =>
  console.log(
    `Usage: insight-charts [options]
    
Options:
  -d, --db-path <path>      Path to the SQLite database (required)
  -o, --output-dir <path>   Output directory for visualization files (default: '.')
  -v, --verbose             Add date and time to log messages
  --help                    Display this help message
  
Environment variables (override the matching options):
  INSIGHT_DB_PATH           Same as --db-path
  INSIGHT_OUTPUT_DIR        Same as --output-dir
  INSIGHT_VERBOSE           Same as --verbose
    
Example:
  insight-charts -d ./db/insights.db -o ./visualizations`,
  )

if (flags.help) {
  printUsage()
  exit(0)
}

if (flags['db-path'] === undefined) {
  console.log('insight-charts: Database path must be specified')
  exit(1)
}

log('Opening SQLite database at:', flags['db-path'])
const db = new DatabaseSync(flags['db-path'])

const summaryStmt = db.prepare('select data from summary order by time desc')
const timeSeriesStmt = db.prepare(
  "select time, data from summary where data not like '{}' and time > '2024-12-21' and time < (select max(time) from summary)",
)

Deno.mkdir(flags['output-dir'], { recursive: true }).catch(() => {})

const charts = [
  { filename: 'osPie.json', generator: osPie, stmt: summaryStmt },
  { filename: 'musicFsPie.json', generator: musicFsPie, stmt: summaryStmt },
  { filename: 'dataFsPie.json', generator: dataFsPie, stmt: summaryStmt },
  { filename: 'playerTypePie.json', generator: playerTypePie, stmt: summaryStmt },
  { filename: 'numInstance.json', generator: numInstanceLine, stmt: timeSeriesStmt },
]

for (const { filename, generator, stmt } of charts) {
  const path = `${flags['output-dir']}/${filename}`
  log(`Saving ${path}`)
  await Deno.writeTextFile(path, generator(stmt))
}

log('All charts saved, bye bye!')
db.close()