Automated music library format conversion with cuesheet detection, tagging support and configurable regex to obtain tags from filenames. Configuration with ini-files to support multiple locations with multiple quality requirements.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

91 lines
2.7 KiB

  1. # -*- coding: UTF-8 -*-
  2. """
  3. Name: ffprobe.py
  4. Porpose: simple cross-platform wrap for ffprobe
  5. Compatibility: Python3
  6. Platform: all platforms
  7. Author: Gianluca Pernigotto <jeanlucperni@gmail.com>
  8. Copyright: (c) 2022/2023 Gianluca Pernigotto <jeanlucperni@gmail.com>
  9. license: GPL3
  10. Rev: Feb.17.2022
  11. Code checker: flake8, pylint
  12. ########################################################
  13. This file is part of FFcuesplitter.
  14. FFcuesplitter is free software: you can redistribute it and/or modify
  15. it under the terms of the GNU General Public License as published by
  16. the Free Software Foundation, either version 3 of the License, or
  17. (at your option) any later version.
  18. FFcuesplitter is distributed in the hope that it will be useful,
  19. but WITHOUT ANY WARRANTY; without even the implied warranty of
  20. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  21. GNU General Public License for more details.
  22. You should have received a copy of the GNU General Public License
  23. along with FFcuesplitter. If not, see <http://www.gnu.org/licenses/>.
  24. """
  25. import subprocess
  26. import shlex
  27. import platform
  28. import json
  29. from ffcuesplitter.exceptions import FFProbeError
  30. from ffcuesplitter.utils import Popen
  31. def from_kwargs_to_args(kwargs):
  32. """
  33. Helper function to build command line
  34. arguments out of dict.
  35. """
  36. args = []
  37. for key in sorted(kwargs.keys()):
  38. val = kwargs[key]
  39. args.append(f'-{key}')
  40. if val is not None:
  41. args.append(f'{val}')
  42. return args
  43. def ffprobe(filename, cmd='ffprobe', **kwargs):
  44. """
  45. Run ffprobe on the specified file and return a
  46. JSON representation of the output.
  47. Raises:
  48. :class:`ffcuesplitter.FFProbeError`: if ffprobe
  49. returns a non-zero exit code;
  50. `ffcuesplitter.FFProbeError` from `OSError`,
  51. `FileNotFoundError` if a generic error.
  52. Usage:
  53. ffprobe(filename,
  54. cmd='/usr/bin oi/ffprobe',
  55. loglevel='error',
  56. hide_banner=None,
  57. etc,
  58. )
  59. """
  60. args = (f'"{cmd}" -show_format -show_streams -of json '
  61. f'{" ".join(from_kwargs_to_args(kwargs))} '
  62. f'"{filename}"'
  63. )
  64. args = shlex.split(args) if platform.system() != 'Windows' else args
  65. try:
  66. with Popen(args,
  67. stdout=subprocess.PIPE,
  68. stderr=subprocess.PIPE,
  69. universal_newlines=True,
  70. ) as proc:
  71. output, error = proc.communicate()
  72. if proc.returncode != 0:
  73. raise FFProbeError(f'ffprobe: {error}')
  74. except (OSError, FileNotFoundError) as excepterr:
  75. raise FFProbeError(excepterr) from excepterr
  76. else:
  77. return json.loads(output)