metadata-readers.js 1.5 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374
  1. import {spawn} from 'node:child_process'
  2. import {promisifyProcess} from './general-util.js'
  3. // Some probers are sorta inconsistent; this function lets them try again if
  4. // they fail the first time.
  5. const tryAgain = function(times, func) {
  6. return async function(...args) {
  7. let n = 0
  8. let ret
  9. while (!ret && n < times) {
  10. try {
  11. ret = await func(...args)
  12. } catch (error) {
  13. if (n + 1 === times) {
  14. throw error
  15. }
  16. }
  17. n++
  18. }
  19. return ret
  20. }
  21. }
  22. const metadataReaders = {}
  23. metadataReaders.ffprobe =
  24. tryAgain(6, async filePath => {
  25. const ffprobe = spawn('ffprobe', [
  26. '-print_format', 'json',
  27. '-show_entries', 'stream=codec_name:format',
  28. '-select_streams', 'a:0',
  29. '-v', 'quiet',
  30. filePath
  31. ])
  32. let probeDataString = ''
  33. ffprobe.stdout.on('data', data => {
  34. probeDataString += data
  35. })
  36. try {
  37. await promisifyProcess(ffprobe, false)
  38. } catch (error) {
  39. return null
  40. }
  41. let data
  42. try {
  43. data = JSON.parse(probeDataString)
  44. } catch (error) {
  45. return null
  46. }
  47. if (typeof data !== 'object' || typeof data.format !== 'object') {
  48. return null
  49. }
  50. return {
  51. duration: parseFloat(data.format.duration),
  52. fileSize: parseInt(data.format.size),
  53. bitrate: parseInt(data.format.bit_rate)
  54. }
  55. })
  56. export default metadataReaders
  57. export function getMetadataReaderFor(_arg) {
  58. // Only the one metadata reader implemented, so far!
  59. return metadataReaders.ffprobe
  60. }