batchmp 1.4__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- batchmp/__init__.py +0 -0
- batchmp/cli/__init__.py +0 -0
- batchmp/cli/base/__init__.py +0 -0
- batchmp/cli/base/bmp_dispatch.py +60 -0
- batchmp/cli/base/bmp_options.py +349 -0
- batchmp/cli/base/vchk.py +47 -0
- batchmp/cli/bmfp/__init__.py +0 -0
- batchmp/cli/bmfp/bmfp_dispatch.py +120 -0
- batchmp/cli/bmfp/bmfp_options.py +442 -0
- batchmp/cli/renamer/__init__.py +0 -0
- batchmp/cli/renamer/renamer_dispatch.py +135 -0
- batchmp/cli/renamer/renamer_options.py +355 -0
- batchmp/cli/tagger/__init__.py +0 -0
- batchmp/cli/tagger/tagger_dispatch.py +143 -0
- batchmp/cli/tagger/tagger_options.py +338 -0
- batchmp/commons/__init__.py +0 -0
- batchmp/commons/chainedhandler.py +102 -0
- batchmp/commons/descriptors.py +173 -0
- batchmp/commons/progressbar.py +154 -0
- batchmp/commons/taskprocessor.py +149 -0
- batchmp/commons/utils.py +194 -0
- batchmp/ffmptools/__init__.py +0 -0
- batchmp/ffmptools/ffcommands/__init__.py +0 -0
- batchmp/ffmptools/ffcommands/cmdopt.py +115 -0
- batchmp/ffmptools/ffcommands/convert.py +130 -0
- batchmp/ffmptools/ffcommands/cuesplit.py +223 -0
- batchmp/ffmptools/ffcommands/denoise.py +173 -0
- batchmp/ffmptools/ffcommands/fragment.py +121 -0
- batchmp/ffmptools/ffcommands/normalize_peak.py +135 -0
- batchmp/ffmptools/ffcommands/segment.py +157 -0
- batchmp/ffmptools/ffcommands/silencesplit.py +159 -0
- batchmp/ffmptools/ffrunner.py +189 -0
- batchmp/ffmptools/ffutils.py +300 -0
- batchmp/ffmptools/processors/__init__.py +0 -0
- batchmp/ffmptools/processors/basefp.py +92 -0
- batchmp/ffmptools/processors/ffentry.py +81 -0
- batchmp/ffmptools/utils/__init__.py +0 -0
- batchmp/ffmptools/utils/cueparse.py +227 -0
- batchmp/ffmptools/utils/cuesheet.py +239 -0
- batchmp/fstools/__init__.py +0 -0
- batchmp/fstools/builders/__init__.py +0 -0
- batchmp/fstools/builders/fsb.py +221 -0
- batchmp/fstools/builders/fsentry.py +60 -0
- batchmp/fstools/builders/fsprms.py +372 -0
- batchmp/fstools/dirtools.py +549 -0
- batchmp/fstools/fsutils.py +272 -0
- batchmp/fstools/rename.py +390 -0
- batchmp/fstools/walker.py +79 -0
- batchmp/tags/__init__.py +0 -0
- batchmp/tags/handlers/__init__.py +0 -0
- batchmp/tags/handlers/basehandler.py +99 -0
- batchmp/tags/handlers/ffmphandler.py +75 -0
- batchmp/tags/handlers/ffmphandlers/__init__.py +0 -0
- batchmp/tags/handlers/ffmphandlers/base.py +243 -0
- batchmp/tags/handlers/mtghandler.py +56 -0
- batchmp/tags/handlers/pmhandler.py +36 -0
- batchmp/tags/handlers/tagsholder.py +264 -0
- batchmp/tags/output/__init__.py +0 -0
- batchmp/tags/output/formatters.py +218 -0
- batchmp/tags/processors/__init__.py +0 -0
- batchmp/tags/processors/basetp.py +266 -0
- batchmp-1.4.dist-info/METADATA +422 -0
- batchmp-1.4.dist-info/RECORD +68 -0
- batchmp-1.4.dist-info/WHEEL +5 -0
- batchmp-1.4.dist-info/entry_points.txt +5 -0
- batchmp-1.4.dist-info/licenses/LICENSE +11 -0
- batchmp-1.4.dist-info/top_level.txt +1 -0
- batchmp-1.4.dist-info/zip-safe +1 -0
batchmp/__init__.py
ADDED
|
File without changes
|
batchmp/cli/__init__.py
ADDED
|
File without changes
|
|
File without changes
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
#!/usr/bin/env python
|
|
2
|
+
# coding=utf8
|
|
3
|
+
## Copyright (c) 2014 Arseniy Kuznetsov
|
|
4
|
+
##
|
|
5
|
+
## This program is free software; you can redistribute it and/or
|
|
6
|
+
## modify it under the terms of the GNU General Public License
|
|
7
|
+
## as published by the Free Software Foundation; either version 2
|
|
8
|
+
## of the License, or (at your option) any later version.
|
|
9
|
+
##
|
|
10
|
+
## This program is distributed in the hope that it will be useful,
|
|
11
|
+
## but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
12
|
+
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
13
|
+
## GNU General Public License for more details.
|
|
14
|
+
|
|
15
|
+
from importlib import metadata
|
|
16
|
+
import batchmp.cli.base.vchk
|
|
17
|
+
from batchmp.cli.base.bmp_options import BatchMPArgParser, BatchMPBaseCommands
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
class BatchMPDispatcher:
|
|
21
|
+
''' Base BatchMP Commands Dispatcher
|
|
22
|
+
'''
|
|
23
|
+
def __init__(self):
|
|
24
|
+
self.option_parser = BatchMPArgParser()
|
|
25
|
+
|
|
26
|
+
# Dispatcher
|
|
27
|
+
def dispatch(self):
|
|
28
|
+
args = self.option_parser.parse_options()
|
|
29
|
+
|
|
30
|
+
if args['sub_cmd'] == BatchMPBaseCommands.VERSION:
|
|
31
|
+
self.print_version()
|
|
32
|
+
|
|
33
|
+
elif args['sub_cmd'] == BatchMPBaseCommands.INFO:
|
|
34
|
+
self.print_info()
|
|
35
|
+
|
|
36
|
+
else:
|
|
37
|
+
# nothing to dispatch
|
|
38
|
+
return False
|
|
39
|
+
|
|
40
|
+
return True
|
|
41
|
+
|
|
42
|
+
# Dispatched methods
|
|
43
|
+
def print_version(self):
|
|
44
|
+
''' Prints BatchMP version info
|
|
45
|
+
'''
|
|
46
|
+
version = metadata.version("batchmp")
|
|
47
|
+
print('BatchMP tools version {}'.format(version))
|
|
48
|
+
|
|
49
|
+
def print_info(self):
|
|
50
|
+
print('\nBatch Media Processing Tools: {}'.format(self.option_parser.script_name))
|
|
51
|
+
print(self.option_parser.description)
|
|
52
|
+
|
|
53
|
+
def main():
|
|
54
|
+
''' BatchMP entry point
|
|
55
|
+
'''
|
|
56
|
+
BatchMPDispatcher().dispatch()
|
|
57
|
+
|
|
58
|
+
if __name__ == '__main__':
|
|
59
|
+
main()
|
|
60
|
+
|
|
@@ -0,0 +1,349 @@
|
|
|
1
|
+
#!/usr/bin/env python
|
|
2
|
+
# coding=utf8
|
|
3
|
+
## Copyright (c) 2014 Arseniy Kuznetsov
|
|
4
|
+
##
|
|
5
|
+
## This program is free software; you can redistribute it and/or
|
|
6
|
+
## modify it under the terms of the GNU General Public License
|
|
7
|
+
## as published by the Free Software Foundation; either version 2
|
|
8
|
+
## of the License, or (at your option) any later version.
|
|
9
|
+
##
|
|
10
|
+
## This program is distributed in the hope that it will be useful,
|
|
11
|
+
## but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
12
|
+
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
13
|
+
## GNU General Public License for more details.
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
""" Global options parsing:
|
|
17
|
+
[-r, --recursive] Recurse into nested folders
|
|
18
|
+
[-el, --end-level] End level for recursion into nested folders
|
|
19
|
+
|
|
20
|
+
[-in, --include] Include names pattern (Unix style)
|
|
21
|
+
[-ex, --exclude] Exclude names pattern (Unix style)
|
|
22
|
+
(excludes hidden files by default)
|
|
23
|
+
[-ad, --all-dirs] Prevent using Include/Exclude patterns on directories
|
|
24
|
+
[-af, --all-files] Prevent using Include/Exclude patterns on files
|
|
25
|
+
(shows hidden files excluded by default)
|
|
26
|
+
|
|
27
|
+
[-s, --sort]{na|nd|sa|sd} Sort order for files / folders (name | date, asc | desc)
|
|
28
|
+
[-ni, nested-indent] Indent for printing nested directories
|
|
29
|
+
[-q, --quiet] Do not visualise changes / show messages during processing
|
|
30
|
+
"""
|
|
31
|
+
|
|
32
|
+
import os, sys, string
|
|
33
|
+
from argparse import ArgumentParser, HelpFormatter
|
|
34
|
+
from distutils.util import strtobool
|
|
35
|
+
from urllib.parse import urlparse
|
|
36
|
+
from batchmp.commons.utils import MiscHelpers
|
|
37
|
+
from batchmp.fstools.fsutils import FSH
|
|
38
|
+
from batchmp.fstools.builders.fsentry import FSEntry, FSEntryDefaults
|
|
39
|
+
from batchmp.ffmptools.ffutils import FFH, FFmpegNotInstalled
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
class BatchMPBaseCommands:
|
|
43
|
+
VERSION = 'version'
|
|
44
|
+
INFO = 'info'
|
|
45
|
+
PRINT = 'print'
|
|
46
|
+
|
|
47
|
+
@classmethod
|
|
48
|
+
def commands_meta(cls):
|
|
49
|
+
return ''.join(('{',
|
|
50
|
+
'{}, '.format(cls.INFO),
|
|
51
|
+
'{}'.format(cls.VERSION),
|
|
52
|
+
'}'))
|
|
53
|
+
|
|
54
|
+
class BatchMPArgParser:
|
|
55
|
+
def __init__(self):
|
|
56
|
+
self._script_name = 'BatchMP'
|
|
57
|
+
self._description = \
|
|
58
|
+
'''
|
|
59
|
+
BatchMP provide management of media files,
|
|
60
|
+
from base properties such as file names
|
|
61
|
+
through tags / artwork metadata to
|
|
62
|
+
advanced operations on the media content.
|
|
63
|
+
|
|
64
|
+
BatchMP tools consist of three main command-line utilities.
|
|
65
|
+
For more information, run:
|
|
66
|
+
$ renamer -h
|
|
67
|
+
$ tagger -h
|
|
68
|
+
$ bmfp -h
|
|
69
|
+
'''
|
|
70
|
+
|
|
71
|
+
@property
|
|
72
|
+
def description(self):
|
|
73
|
+
return self._description
|
|
74
|
+
|
|
75
|
+
@property
|
|
76
|
+
def script_name(self):
|
|
77
|
+
return self._script_name
|
|
78
|
+
|
|
79
|
+
# Args parsing
|
|
80
|
+
def parse_options(self):
|
|
81
|
+
''' Common workflow for parsing options
|
|
82
|
+
'''
|
|
83
|
+
parser = ArgumentParser(prog = self._script_name, description = self._description,
|
|
84
|
+
formatter_class=BatchMPHelpFormatter)
|
|
85
|
+
|
|
86
|
+
self.parse_global_options(parser)
|
|
87
|
+
|
|
88
|
+
self.parse_commands(parser)
|
|
89
|
+
|
|
90
|
+
args = vars(parser.parse_args())
|
|
91
|
+
|
|
92
|
+
self.check_args(args, parser)
|
|
93
|
+
|
|
94
|
+
return args
|
|
95
|
+
|
|
96
|
+
def parse_global_options(self, parser):
|
|
97
|
+
''' Parses global options
|
|
98
|
+
'''
|
|
99
|
+
source_mode_group = parser.add_argument_group('Input source mode')
|
|
100
|
+
source_mode_group.add_argument("-d", "--dir", dest = "dir",
|
|
101
|
+
type = lambda d: self._is_valid_dir_path(parser, d),
|
|
102
|
+
help = "Source directory (default is current directory)",
|
|
103
|
+
default = os.curdir)
|
|
104
|
+
source_mode_group.add_argument("-f", "--file", dest = "file",
|
|
105
|
+
type = lambda f: self._is_valid_file_path(parser, f),
|
|
106
|
+
help = "File to process")
|
|
107
|
+
|
|
108
|
+
recursive_mode_group = parser.add_argument_group('Recursion mode')
|
|
109
|
+
recursive_mode_group.add_argument("-r", "--recursive", dest = "recursive",
|
|
110
|
+
help = "Recurse into nested folders",
|
|
111
|
+
action = 'store_true')
|
|
112
|
+
recursive_mode_group.add_argument("-el", "--end-level", dest = "end_level",
|
|
113
|
+
help = "End level for recursion into nested folders",
|
|
114
|
+
type = int,
|
|
115
|
+
default = 0)
|
|
116
|
+
|
|
117
|
+
include_mode_group = parser.add_argument_group('Filter files or folders')
|
|
118
|
+
include_mode_group.add_argument("-in", "--include", dest = "include",
|
|
119
|
+
help = "Include: Unix-style name patterns separated by ';'",
|
|
120
|
+
type = str,
|
|
121
|
+
default = FSEntryDefaults.DEFAULT_INCLUDE)
|
|
122
|
+
include_mode_group.add_argument("-ex", "--exclude", dest = "exclude",
|
|
123
|
+
help = "Exclude: Unix-style name patterns separated by ';' (excludes hidden files by default)",
|
|
124
|
+
type = str,
|
|
125
|
+
default = FSEntryDefaults.DEFAULT_EXCLUDE)
|
|
126
|
+
include_mode_group.add_argument("-ad", "--all-dirs", dest = "all_dirs",
|
|
127
|
+
help = "Disable Include/Exclude patterns on directories",
|
|
128
|
+
action = 'store_true')
|
|
129
|
+
include_mode_group.add_argument("-af", "--all-files", dest = "all_files",
|
|
130
|
+
help = "Disable Include/Exclude patterns on files (shows hidden files excluded by default)",
|
|
131
|
+
action = 'store_true')
|
|
132
|
+
|
|
133
|
+
media_types_group = parser.add_argument_group('File media types')
|
|
134
|
+
media_types_group.add_argument("-ft", "--file-type", dest = "file_type",
|
|
135
|
+
help = "File Media Type",
|
|
136
|
+
type = str,
|
|
137
|
+
choices = ['image', 'video', 'audio', 'media', 'nonmedia', 'playable', 'nonplayable', 'any'],
|
|
138
|
+
default = FSEntryDefaults.DEFAULT_FILE_TYPE)
|
|
139
|
+
media_types_group.add_argument("-ms", "--media-scan", dest = "media_scan",
|
|
140
|
+
help = "Scan for media types, instead of using file extensions (can take a long time)",
|
|
141
|
+
action = 'store_true')
|
|
142
|
+
|
|
143
|
+
|
|
144
|
+
# Add Default Miscellaneous Group
|
|
145
|
+
self._add_arg_misc_group(parser)
|
|
146
|
+
|
|
147
|
+
def parse_commands(self, parser):
|
|
148
|
+
''' Specific commands parsing
|
|
149
|
+
'''
|
|
150
|
+
subparsers = parser.add_subparsers(dest = 'sub_cmd',
|
|
151
|
+
title = 'BatchMP commands',
|
|
152
|
+
metavar = BatchMPBaseCommands.commands_meta())
|
|
153
|
+
self._add_version(subparsers)
|
|
154
|
+
self._add_info(subparsers)
|
|
155
|
+
|
|
156
|
+
# Args checking
|
|
157
|
+
def check_cmd_args(self, args, parser,
|
|
158
|
+
show_help = False,
|
|
159
|
+
exit = False):
|
|
160
|
+
if not args.get('sub_cmd'):
|
|
161
|
+
if show_help:
|
|
162
|
+
parser.print_help()
|
|
163
|
+
if exit:
|
|
164
|
+
sys.exit(1)
|
|
165
|
+
|
|
166
|
+
# if not exiting, need to default
|
|
167
|
+
self.default_command(args, parser)
|
|
168
|
+
|
|
169
|
+
def default_command(self, args, parser):
|
|
170
|
+
args['sub_cmd'] = BatchMPBaseCommands.INFO
|
|
171
|
+
|
|
172
|
+
def check_args(self, args, parser):
|
|
173
|
+
''' Validation of supplied CLI arguments
|
|
174
|
+
'''
|
|
175
|
+
# check if there is a cmd to execute
|
|
176
|
+
self.check_cmd_args(args, parser)
|
|
177
|
+
|
|
178
|
+
# if input source is a file, need to adjust
|
|
179
|
+
if args['file']:
|
|
180
|
+
args['dir'] = os.path.dirname(args['file'])
|
|
181
|
+
args['include'] = os.path.basename(args['file'])
|
|
182
|
+
args['exclude'] = ''
|
|
183
|
+
args['end_level'] = 0
|
|
184
|
+
args['all_files'] = False
|
|
185
|
+
args['all_dirs'] = False
|
|
186
|
+
|
|
187
|
+
# check recursion
|
|
188
|
+
if args['recursive'] and args['end_level'] == 0:
|
|
189
|
+
args['end_level'] = sys.maxsize
|
|
190
|
+
|
|
191
|
+
|
|
192
|
+
if args['media_scan']:
|
|
193
|
+
if not FFH.ffmpeg_installed():
|
|
194
|
+
print('Advanced media-related operations require FFmpeg')
|
|
195
|
+
print(FFmpegNotInstalled().default_message)
|
|
196
|
+
sys.exit(0)
|
|
197
|
+
|
|
198
|
+
if args['sub_cmd'] == BatchMPBaseCommands.PRINT:
|
|
199
|
+
if args['start_level'] != 0:
|
|
200
|
+
if args['file']:
|
|
201
|
+
print ('Start Level parameter requires a source directory\n Ignoring requested Start Level...')
|
|
202
|
+
args['start_level'] = 0
|
|
203
|
+
elif args['end_level'] < args['start_level']:
|
|
204
|
+
''' print ('Start Level should be greater than or equal to the Recursion End Level Global Option\n'
|
|
205
|
+
'... Adjusting End Level to: {}'.format(args['start_level']))
|
|
206
|
+
'''
|
|
207
|
+
args['end_level'] = args['start_level']
|
|
208
|
+
|
|
209
|
+
# Internal Helpers
|
|
210
|
+
@staticmethod
|
|
211
|
+
def _is_valid_dir_path(parser, path_arg):
|
|
212
|
+
""" Checks if path_arg is a valid dir path
|
|
213
|
+
"""
|
|
214
|
+
path_arg = FSH.full_path(path_arg)
|
|
215
|
+
if not (os.path.exists(path_arg) and os.path.isdir(path_arg)):
|
|
216
|
+
parser.error('"{}" does not seem to be an existing directory path'.format(path_arg))
|
|
217
|
+
else:
|
|
218
|
+
return path_arg
|
|
219
|
+
|
|
220
|
+
@staticmethod
|
|
221
|
+
def _is_valid_file_path(parser, path_arg):
|
|
222
|
+
""" Checks if path_arg is a valid file path
|
|
223
|
+
"""
|
|
224
|
+
path_arg = FSH.full_path(path_arg)
|
|
225
|
+
if not (os.path.exists(path_arg) and os.path.isfile(path_arg)):
|
|
226
|
+
parser.error('"{}" does not seem to be an existing file path'.format(path_arg))
|
|
227
|
+
else:
|
|
228
|
+
return path_arg
|
|
229
|
+
|
|
230
|
+
@staticmethod
|
|
231
|
+
def _is_boolean(parser, bool_arg):
|
|
232
|
+
""" Checks if bool_arg can be interpreted as a boolean value
|
|
233
|
+
"""
|
|
234
|
+
try:
|
|
235
|
+
bool_arg = True if strtobool(bool_arg) else False
|
|
236
|
+
except ValueError:
|
|
237
|
+
parser.error('"{}": Please enter a boolean value'.format(bool_arg))
|
|
238
|
+
return False
|
|
239
|
+
|
|
240
|
+
@staticmethod
|
|
241
|
+
def _is_valid_url(parser, url_arg):
|
|
242
|
+
url_parts = urlparse(url_arg)
|
|
243
|
+
|
|
244
|
+
def _parser_error():
|
|
245
|
+
parser.error('"{}": Please enter a valid URL'.format(url_arg))
|
|
246
|
+
|
|
247
|
+
if url_parts.scheme in (None, '') and url_parts.netloc in (None, ''):
|
|
248
|
+
_parser_error()
|
|
249
|
+
|
|
250
|
+
if url_parts.scheme == 'file':
|
|
251
|
+
if url_parts.netloc == '~':
|
|
252
|
+
fpath = '~{}'.format(url_parts.path)
|
|
253
|
+
else:
|
|
254
|
+
fpath = url_parts.path
|
|
255
|
+
return BatchMPArgParser._is_valid_file_path(parser, fpath)
|
|
256
|
+
|
|
257
|
+
if not set(url_parts.netloc).issubset(set(string.ascii_letters + string.digits + '-.')):
|
|
258
|
+
_parser_error()
|
|
259
|
+
|
|
260
|
+
if not url_parts.scheme in ['http', 'https', 'ftp', 'file']:
|
|
261
|
+
_parser_error()
|
|
262
|
+
|
|
263
|
+
return url_arg
|
|
264
|
+
|
|
265
|
+
@staticmethod
|
|
266
|
+
def _is_valid_url_or_file_path(parser, url_or_file_path_arg):
|
|
267
|
+
url_parts = urlparse(url_or_file_path_arg)
|
|
268
|
+
if url_parts.scheme in (None, '') and url_parts.netloc in (None, ''):
|
|
269
|
+
return BatchMPArgParser._is_valid_file_path(parser, url_or_file_path_arg)
|
|
270
|
+
else:
|
|
271
|
+
return BatchMPArgParser._is_valid_url(parser, url_or_file_path_arg)
|
|
272
|
+
|
|
273
|
+
@staticmethod
|
|
274
|
+
def _is_timedelta(parser, td_arg):
|
|
275
|
+
try:
|
|
276
|
+
td = MiscHelpers.time_delta(td_arg)
|
|
277
|
+
except ValueError:
|
|
278
|
+
parser.error('"{}": Please enter a valid value, ' \
|
|
279
|
+
'in seconds or in the "hh:mm:ss[.xxx]" format'.format(td_arg))
|
|
280
|
+
return td
|
|
281
|
+
|
|
282
|
+
# Processing mode for relevant commands
|
|
283
|
+
@staticmethod
|
|
284
|
+
def _add_arg_display_curent_state_mode(parser):
|
|
285
|
+
parser.add_argument('-dc', '--display-current', dest = 'display_current',
|
|
286
|
+
help ='Unless in quiet mode, display current (pre-processing) state in the confirmation propmt',
|
|
287
|
+
action = 'store_true')
|
|
288
|
+
|
|
289
|
+
@staticmethod
|
|
290
|
+
def _add_arg_misc_group(parser):
|
|
291
|
+
misc_group = parser.add_argument_group('Miscellaneous')
|
|
292
|
+
misc_group.add_argument('-s', '--sort', dest = 'sort',
|
|
293
|
+
help = "Sorting for files ('na', i.e. by name ascending by default)",
|
|
294
|
+
type = str,
|
|
295
|
+
choices = ['na', 'nd', 'sa', 'sd'],
|
|
296
|
+
default = FSEntryDefaults.DEFAULT_SORT)
|
|
297
|
+
misc_group.add_argument('-ni', '--nested_indent', dest = 'nested_indent',
|
|
298
|
+
help = "Indent for printing nested directories",
|
|
299
|
+
type = str,
|
|
300
|
+
default = ' ')
|
|
301
|
+
misc_group.add_argument("-q", "--quiet", dest = 'quiet',
|
|
302
|
+
help = "Disable visualising changes & displaying info messages during processing",
|
|
303
|
+
action = 'store_true')
|
|
304
|
+
|
|
305
|
+
@staticmethod
|
|
306
|
+
def _add_version(parser):
|
|
307
|
+
''' Adds the version command
|
|
308
|
+
'''
|
|
309
|
+
parser.add_parser(BatchMPBaseCommands.VERSION,
|
|
310
|
+
description = 'Displays BatchMP version info',
|
|
311
|
+
formatter_class=BatchMPHelpFormatter)
|
|
312
|
+
|
|
313
|
+
@staticmethod
|
|
314
|
+
def _add_info(parser):
|
|
315
|
+
''' Adds the info command
|
|
316
|
+
'''
|
|
317
|
+
parser.add_parser(BatchMPBaseCommands.INFO,
|
|
318
|
+
description = 'Displays BatchMP info',
|
|
319
|
+
formatter_class=BatchMPHelpFormatter)
|
|
320
|
+
|
|
321
|
+
|
|
322
|
+
|
|
323
|
+
class BatchMPHelpFormatter(HelpFormatter):
|
|
324
|
+
''' Custom ArgumentParser formatter
|
|
325
|
+
Disables double metavar display, showing it only for long-named options
|
|
326
|
+
'''
|
|
327
|
+
def _format_action_invocation(self, action):
|
|
328
|
+
if not action.option_strings:
|
|
329
|
+
metavar, = self._metavar_formatter(action, action.dest)(1)
|
|
330
|
+
return metavar
|
|
331
|
+
else:
|
|
332
|
+
parts = []
|
|
333
|
+
# if the Optional doesn't take a value, format is:
|
|
334
|
+
# -s, --long
|
|
335
|
+
if action.nargs == 0:
|
|
336
|
+
parts.extend(action.option_strings)
|
|
337
|
+
|
|
338
|
+
# if the Optional takes a value, format is:
|
|
339
|
+
# -s ARGS, --long ARGS
|
|
340
|
+
# change to
|
|
341
|
+
# -s, --long ARGS
|
|
342
|
+
else:
|
|
343
|
+
default = action.dest.upper()
|
|
344
|
+
args_string = self._format_args(action, default)
|
|
345
|
+
for option_string in action.option_strings:
|
|
346
|
+
#parts.append('%s %s' % (option_string, args_string))
|
|
347
|
+
parts.append('%s' % option_string)
|
|
348
|
+
parts[-1] += ' %s'%args_string
|
|
349
|
+
return ', '.join(parts)
|
batchmp/cli/base/vchk.py
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
#!/usr/bin/env python
|
|
2
|
+
# coding=utf8
|
|
3
|
+
## Copyright (c) 2014 Arseniy Kuznetsov
|
|
4
|
+
##
|
|
5
|
+
## This program is free software; you can redistribute it and/or
|
|
6
|
+
## modify it under the terms of the GNU General Public License
|
|
7
|
+
## as published by the Free Software Foundation; either version 2
|
|
8
|
+
## of the License, or (at your option) any later version.
|
|
9
|
+
##
|
|
10
|
+
## This program is distributed in the hope that it will be useful,
|
|
11
|
+
## but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
12
|
+
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
13
|
+
## GNU General Public License for more details.
|
|
14
|
+
|
|
15
|
+
''' Python version check
|
|
16
|
+
'''
|
|
17
|
+
|
|
18
|
+
from __future__ import print_function
|
|
19
|
+
import sys
|
|
20
|
+
|
|
21
|
+
def check_version():
|
|
22
|
+
if sys.version_info.major < 3:
|
|
23
|
+
print(\
|
|
24
|
+
'''
|
|
25
|
+
Batch Media Processing Tools require
|
|
26
|
+
Python version 3.6 or later.
|
|
27
|
+
|
|
28
|
+
You can create an isolated Python 3.6 environment
|
|
29
|
+
with the virtualenv tool:
|
|
30
|
+
http://docs.python-guide.org/en/latest/dev/virtualenvs
|
|
31
|
+
|
|
32
|
+
''')
|
|
33
|
+
sys.exit(1)
|
|
34
|
+
elif sys.version_info.major == 3 and sys.version_info.minor < 6:
|
|
35
|
+
print(\
|
|
36
|
+
'''
|
|
37
|
+
|
|
38
|
+
Batch Media Processing Tools require
|
|
39
|
+
Python version 3.6 or later.
|
|
40
|
+
|
|
41
|
+
Please upgrade to the latest Python 3.x version.
|
|
42
|
+
|
|
43
|
+
''')
|
|
44
|
+
sys.exit(1)
|
|
45
|
+
|
|
46
|
+
# check
|
|
47
|
+
check_version()
|
|
File without changes
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
#!/usr/bin/env python
|
|
2
|
+
# coding=utf8
|
|
3
|
+
## Copyright (c) 2014 Arseniy Kuznetsov
|
|
4
|
+
##
|
|
5
|
+
## This program is free software; you can redistribute it and/or
|
|
6
|
+
## modify it under the terms of the GNU General Public License
|
|
7
|
+
## as published by the Free Software Foundation; either version 2
|
|
8
|
+
## of the License, or (at your option) any later version.
|
|
9
|
+
##
|
|
10
|
+
## This program is distributed in the hope that it will be useful,
|
|
11
|
+
## but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
12
|
+
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
13
|
+
## GNU General Public License for more details.
|
|
14
|
+
|
|
15
|
+
from batchmp.cli.base.bmp_dispatch import BatchMPDispatcher
|
|
16
|
+
from batchmp.cli.bmfp.bmfp_options import BMFPArgParser, BMFPCommands
|
|
17
|
+
from batchmp.ffmptools.ffcommands.convert import Convertor
|
|
18
|
+
from batchmp.ffmptools.ffcommands.segment import Segmenter
|
|
19
|
+
from batchmp.ffmptools.ffcommands.fragment import Fragmenter
|
|
20
|
+
from batchmp.ffmptools.ffcommands.silencesplit import SilenceSplitter
|
|
21
|
+
from batchmp.ffmptools.ffcommands.denoise import Denoiser
|
|
22
|
+
from batchmp.ffmptools.ffcommands.normalize_peak import PeakNormalizer
|
|
23
|
+
from batchmp.ffmptools.ffcommands.cuesplit import CueSplitter
|
|
24
|
+
from batchmp.ffmptools.processors.basefp import BaseFFProcessor
|
|
25
|
+
from batchmp.tags.output.formatters import OutputFormatType
|
|
26
|
+
from batchmp.ffmptools.processors.ffentry import FFEntryParams, FFEntryParamsExt, FFEntryParamsSilenceSplit
|
|
27
|
+
|
|
28
|
+
class BMFPDispatcher(BatchMPDispatcher):
|
|
29
|
+
''' BMFP commands Dispatcher
|
|
30
|
+
'''
|
|
31
|
+
def __init__(self):
|
|
32
|
+
self.option_parser = BMFPArgParser()
|
|
33
|
+
|
|
34
|
+
# Dispatcher
|
|
35
|
+
def dispatch(self):
|
|
36
|
+
''' Dispatches BMFP commands
|
|
37
|
+
'''
|
|
38
|
+
if not super().dispatch():
|
|
39
|
+
args = self.option_parser.parse_options()
|
|
40
|
+
if args['sub_cmd'] == BMFPCommands.PRINT:
|
|
41
|
+
self.print_dir(args)
|
|
42
|
+
|
|
43
|
+
elif args['sub_cmd'] == BMFPCommands.CONVERT:
|
|
44
|
+
self.convert(args)
|
|
45
|
+
|
|
46
|
+
elif args['sub_cmd'] == BMFPCommands.DENOISE:
|
|
47
|
+
self.denoise(args)
|
|
48
|
+
|
|
49
|
+
elif args['sub_cmd'] == BMFPCommands.NORMALIZE:
|
|
50
|
+
self.normalize(args)
|
|
51
|
+
|
|
52
|
+
elif args['sub_cmd'] == BMFPCommands.FRAGMENT:
|
|
53
|
+
self.fragment(args)
|
|
54
|
+
|
|
55
|
+
elif args['sub_cmd'] == BMFPCommands.SEGMENT:
|
|
56
|
+
self.segment(args)
|
|
57
|
+
|
|
58
|
+
elif args['sub_cmd'] == BMFPCommands.SILENCESPLIT:
|
|
59
|
+
self.silence_split(args)
|
|
60
|
+
|
|
61
|
+
elif args['sub_cmd'] == BMFPCommands.CUESPLIT:
|
|
62
|
+
self.cue_split(args)
|
|
63
|
+
|
|
64
|
+
else:
|
|
65
|
+
print('Nothing to dispatch')
|
|
66
|
+
return False
|
|
67
|
+
|
|
68
|
+
return True
|
|
69
|
+
|
|
70
|
+
# Dispatched Methods
|
|
71
|
+
def print_dir(self, args):
|
|
72
|
+
ff_entry_params = FFEntryParams(args)
|
|
73
|
+
BaseFFProcessor().print_dir(ff_entry_params,
|
|
74
|
+
show_stats = True,
|
|
75
|
+
format = OutputFormatType.STATS if not args['show_tags'] else OutputFormatType.FULL,
|
|
76
|
+
show_volume = args['show_volume'], show_silence = args['show_silence'])
|
|
77
|
+
|
|
78
|
+
def convert(self, args):
|
|
79
|
+
ff_entry_params = FFEntryParamsExt(args)
|
|
80
|
+
Convertor().convert(ff_entry_params)
|
|
81
|
+
|
|
82
|
+
def denoise(self, args):
|
|
83
|
+
ff_entry_params = FFEntryParamsExt(args)
|
|
84
|
+
Denoiser().apply_af_filters(ff_entry_params,
|
|
85
|
+
num_passes=args['num_passes'],
|
|
86
|
+
highpass=args['highpass'],
|
|
87
|
+
lowpass=args['lowpass'])
|
|
88
|
+
|
|
89
|
+
def normalize(self, args):
|
|
90
|
+
ff_entry_params = FFEntryParamsExt(args)
|
|
91
|
+
PeakNormalizer().peak_normalize(ff_entry_params)
|
|
92
|
+
|
|
93
|
+
def fragment(self, args):
|
|
94
|
+
ff_entry_params = FFEntryParamsExt(args)
|
|
95
|
+
Fragmenter().fragment(ff_entry_params,
|
|
96
|
+
fragment_starttime = args['fragment_starttime'].total_seconds(),
|
|
97
|
+
fragment_duration = args['fragment_duration'].total_seconds(),
|
|
98
|
+
fragment_trim = args['fragment_trim'].total_seconds(),
|
|
99
|
+
)
|
|
100
|
+
|
|
101
|
+
def segment(self, args):
|
|
102
|
+
ff_entry_params = FFEntryParamsExt(args)
|
|
103
|
+
Segmenter().segment(ff_entry_params,
|
|
104
|
+
segment_size_MB = args['segment_filesize'],
|
|
105
|
+
segment_length_secs = args['segment_duration'].total_seconds(),
|
|
106
|
+
reset_timestamps = args['reset_timestamps'])
|
|
107
|
+
|
|
108
|
+
def silence_split(self, args):
|
|
109
|
+
ff_entry_params = FFEntryParamsSilenceSplit(args)
|
|
110
|
+
SilenceSplitter().silence_split(ff_entry_params)
|
|
111
|
+
|
|
112
|
+
def cue_split(self, args):
|
|
113
|
+
ff_entry_params = FFEntryParamsExt(args)
|
|
114
|
+
CueSplitter().cue_split(ff_entry_params, encoding = args['encoding'])
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
def main():
|
|
118
|
+
''' BMFP entry point
|
|
119
|
+
'''
|
|
120
|
+
BMFPDispatcher().dispatch()
|