« get me outta code hell

metadata-readers.js - mtui - Music Text User Interface - user-friendly command line music player
about summary refs log tree commit diff
path: root/metadata-readers.js
blob: 64f413a07d463caff367ecf6aa21d256fae875fb (plain)
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
const { promisifyProcess } = require('./general-util')
const { spawn } = require('child_process')

// Some probers are sorta inconsistent; this function lets them try again if
// they fail the first time.
const tryAgain = function(times, func) {
  return async function(...args) {
    let n = 0
    let ret
    while (!ret && n < times) {
      try {
        ret = await func(...args)
      } catch (error) {
        if (n + 1 === times) {
          throw error
        }
      }
      n++
    }
    return ret
  }
}

const metadataReaders = {
  ffprobe: tryAgain(6, async filePath => {
    const ffprobe = spawn('ffprobe', [
      '-print_format', 'json',
      '-show_entries', 'stream=codec_name:format',
      '-select_streams', 'a:0',
      '-v', 'quiet',
      filePath
    ])

    let probeDataString = ''

    ffprobe.stdout.on('data', data => {
      probeDataString += data
    })

    await promisifyProcess(ffprobe, false)

    let data

    try {
      data = JSON.parse(probeDataString)
    } catch (error) {
      return null
    }

    if (typeof data !== 'object' || typeof data.format !== 'object') {
      return null
    }

    return {
      duration: parseFloat(data.format.duration),
      fileSize: parseInt(data.format.size),
      bitrate: parseInt(data.format.bit_rate)
    }
  }),

  getMetadataReaderFor: arg => {
    return metadataReaders.ffprobe
  }
}

module.exports = metadataReaders