batchmp 1.0__tar.gz → 1.4.2__tar.gz
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-1.0/batchmp.egg-info → batchmp-1.4.2}/PKG-INFO +108 -16
- batchmp-1.0/PKG-INFO → batchmp-1.4.2/README.md +86 -41
- {batchmp-1.0 → batchmp-1.4.2}/batchmp/cli/base/bmp_dispatch.py +2 -2
- {batchmp-1.0 → batchmp-1.4.2}/batchmp/cli/base/bmp_options.py +1 -1
- {batchmp-1.0 → batchmp-1.4.2}/batchmp/cli/bmfp/bmfp_dispatch.py +3 -1
- {batchmp-1.0 → batchmp-1.4.2}/batchmp/cli/bmfp/bmfp_options.py +8 -3
- {batchmp-1.0 → batchmp-1.4.2}/batchmp/cli/renamer/renamer_dispatch.py +15 -4
- {batchmp-1.0 → batchmp-1.4.2}/batchmp/cli/renamer/renamer_options.py +32 -1
- {batchmp-1.0 → batchmp-1.4.2}/batchmp/commons/utils.py +10 -0
- {batchmp-1.0 → batchmp-1.4.2}/batchmp/ffmptools/ffcommands/cuesplit.py +3 -3
- {batchmp-1.0 → batchmp-1.4.2}/batchmp/ffmptools/ffcommands/fragment.py +13 -3
- {batchmp-1.0 → batchmp-1.4.2}/batchmp/ffmptools/ffcommands/segment.py +7 -7
- {batchmp-1.0 → batchmp-1.4.2}/batchmp/ffmptools/ffutils.py +5 -5
- {batchmp-1.0 → batchmp-1.4.2}/batchmp/ffmptools/utils/cueparse.py +2 -2
- {batchmp-1.0 → batchmp-1.4.2}/batchmp/fstools/builders/fsb.py +60 -3
- {batchmp-1.0 → batchmp-1.4.2}/batchmp/fstools/builders/fsprms.py +10 -3
- {batchmp-1.0 → batchmp-1.4.2}/batchmp/fstools/dirtools.py +78 -9
- {batchmp-1.0 → batchmp-1.4.2}/batchmp/fstools/rename.py +11 -0
- batchmp-1.4.2/batchmp/fstools/virtual_organizer.py +301 -0
- {batchmp-1.0 → batchmp-1.4.2}/batchmp/fstools/walker.py +2 -2
- {batchmp-1.0 → batchmp-1.4.2}/batchmp/tags/handlers/mtghandler.py +1 -2
- {batchmp-1.0 → batchmp-1.4.2}/batchmp/tags/processors/basetp.py +1 -1
- batchmp-1.0/README.md → batchmp-1.4.2/batchmp.egg-info/PKG-INFO +133 -12
- {batchmp-1.0 → batchmp-1.4.2}/batchmp.egg-info/SOURCES.txt +2 -2
- batchmp-1.4.2/batchmp.egg-info/requires.txt +8 -0
- batchmp-1.4.2/pyproject.toml +3 -0
- {batchmp-1.0 → batchmp-1.4.2}/setup.py +9 -5
- batchmp-1.0/batchmp/tags/extern/mediafile.py +0 -1889
- batchmp-1.0/batchmp/tags/processors/__init__.py +0 -0
- batchmp-1.0/batchmp.egg-info/requires.txt +0 -2
- {batchmp-1.0 → batchmp-1.4.2}/LICENSE +0 -0
- {batchmp-1.0 → batchmp-1.4.2}/batchmp/__init__.py +0 -0
- {batchmp-1.0 → batchmp-1.4.2}/batchmp/cli/__init__.py +0 -0
- {batchmp-1.0 → batchmp-1.4.2}/batchmp/cli/base/__init__.py +0 -0
- {batchmp-1.0 → batchmp-1.4.2}/batchmp/cli/base/vchk.py +0 -0
- {batchmp-1.0 → batchmp-1.4.2}/batchmp/cli/bmfp/__init__.py +0 -0
- {batchmp-1.0 → batchmp-1.4.2}/batchmp/cli/renamer/__init__.py +0 -0
- {batchmp-1.0 → batchmp-1.4.2}/batchmp/cli/tagger/__init__.py +0 -0
- {batchmp-1.0 → batchmp-1.4.2}/batchmp/cli/tagger/tagger_dispatch.py +0 -0
- {batchmp-1.0 → batchmp-1.4.2}/batchmp/cli/tagger/tagger_options.py +0 -0
- {batchmp-1.0 → batchmp-1.4.2}/batchmp/commons/__init__.py +0 -0
- {batchmp-1.0 → batchmp-1.4.2}/batchmp/commons/chainedhandler.py +0 -0
- {batchmp-1.0 → batchmp-1.4.2}/batchmp/commons/descriptors.py +0 -0
- {batchmp-1.0 → batchmp-1.4.2}/batchmp/commons/progressbar.py +0 -0
- {batchmp-1.0 → batchmp-1.4.2}/batchmp/commons/taskprocessor.py +0 -0
- {batchmp-1.0 → batchmp-1.4.2}/batchmp/ffmptools/__init__.py +0 -0
- {batchmp-1.0 → batchmp-1.4.2}/batchmp/ffmptools/ffcommands/__init__.py +0 -0
- {batchmp-1.0 → batchmp-1.4.2}/batchmp/ffmptools/ffcommands/cmdopt.py +0 -0
- {batchmp-1.0 → batchmp-1.4.2}/batchmp/ffmptools/ffcommands/convert.py +0 -0
- {batchmp-1.0 → batchmp-1.4.2}/batchmp/ffmptools/ffcommands/denoise.py +0 -0
- {batchmp-1.0 → batchmp-1.4.2}/batchmp/ffmptools/ffcommands/normalize_peak.py +0 -0
- {batchmp-1.0 → batchmp-1.4.2}/batchmp/ffmptools/ffcommands/silencesplit.py +0 -0
- {batchmp-1.0 → batchmp-1.4.2}/batchmp/ffmptools/ffrunner.py +0 -0
- {batchmp-1.0 → batchmp-1.4.2}/batchmp/ffmptools/processors/__init__.py +0 -0
- {batchmp-1.0 → batchmp-1.4.2}/batchmp/ffmptools/processors/basefp.py +0 -0
- {batchmp-1.0 → batchmp-1.4.2}/batchmp/ffmptools/processors/ffentry.py +0 -0
- {batchmp-1.0 → batchmp-1.4.2}/batchmp/ffmptools/utils/__init__.py +0 -0
- {batchmp-1.0 → batchmp-1.4.2}/batchmp/ffmptools/utils/cuesheet.py +0 -0
- {batchmp-1.0 → batchmp-1.4.2}/batchmp/fstools/__init__.py +0 -0
- {batchmp-1.0 → batchmp-1.4.2}/batchmp/fstools/builders/__init__.py +0 -0
- {batchmp-1.0 → batchmp-1.4.2}/batchmp/fstools/builders/fsentry.py +0 -0
- {batchmp-1.0 → batchmp-1.4.2}/batchmp/fstools/fsutils.py +0 -0
- {batchmp-1.0 → batchmp-1.4.2}/batchmp/tags/__init__.py +0 -0
- {batchmp-1.0/batchmp/tags/extern → batchmp-1.4.2/batchmp/tags/handlers}/__init__.py +0 -0
- {batchmp-1.0 → batchmp-1.4.2}/batchmp/tags/handlers/basehandler.py +0 -0
- {batchmp-1.0 → batchmp-1.4.2}/batchmp/tags/handlers/ffmphandler.py +0 -0
- {batchmp-1.0/batchmp/tags/handlers → batchmp-1.4.2/batchmp/tags/handlers/ffmphandlers}/__init__.py +0 -0
- {batchmp-1.0 → batchmp-1.4.2}/batchmp/tags/handlers/ffmphandlers/base.py +0 -0
- {batchmp-1.0 → batchmp-1.4.2}/batchmp/tags/handlers/pmhandler.py +0 -0
- {batchmp-1.0 → batchmp-1.4.2}/batchmp/tags/handlers/tagsholder.py +0 -0
- {batchmp-1.0/batchmp/tags/handlers/ffmphandlers → batchmp-1.4.2/batchmp/tags/output}/__init__.py +0 -0
- {batchmp-1.0 → batchmp-1.4.2}/batchmp/tags/output/formatters.py +0 -0
- {batchmp-1.0/batchmp/tags/output → batchmp-1.4.2/batchmp/tags/processors}/__init__.py +0 -0
- {batchmp-1.0 → batchmp-1.4.2}/batchmp.egg-info/dependency_links.txt +0 -0
- {batchmp-1.0 → batchmp-1.4.2}/batchmp.egg-info/entry_points.txt +0 -0
- {batchmp-1.0 → batchmp-1.4.2}/batchmp.egg-info/top_level.txt +0 -0
- {batchmp-1.0 → batchmp-1.4.2}/batchmp.egg-info/zip-safe +0 -0
- {batchmp-1.0 → batchmp-1.4.2}/setup.cfg +0 -0
|
@@ -1,14 +1,13 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
2
|
Name: batchmp
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.4.2
|
|
4
4
|
Summary: Command-line tools for batch media processing
|
|
5
5
|
Home-page: https://github.com/akpw/batch-mp-tools
|
|
6
6
|
Author: Arseniy Kuznetsov
|
|
7
7
|
Author-email: k.arseniy@gmail.com
|
|
8
|
-
License:
|
|
8
|
+
License: GPL-2.0-or-later
|
|
9
9
|
Keywords: batch processing media video audio CLI rename tags ID3
|
|
10
10
|
Classifier: Development Status :: 4 - Beta
|
|
11
|
-
Classifier: License :: OSI Approved :: GNU General Public License v2 or later (GPLv2+)
|
|
12
11
|
Classifier: Programming Language :: Python
|
|
13
12
|
Classifier: Programming Language :: Python :: 3.6
|
|
14
13
|
Classifier: Programming Language :: Python :: 3 :: Only
|
|
@@ -26,6 +25,25 @@ Classifier: Topic :: Software Development :: Libraries
|
|
|
26
25
|
Classifier: Topic :: Utilities
|
|
27
26
|
Description-Content-Type: text/markdown
|
|
28
27
|
License-File: LICENSE
|
|
28
|
+
Requires-Dist: mutagen>=1.27
|
|
29
|
+
Requires-Dist: pygtrie>=2.3.2
|
|
30
|
+
Requires-Dist: filetype>=1.0.7
|
|
31
|
+
Requires-Dist: mediafile>=0.13.0
|
|
32
|
+
Provides-Extra: test
|
|
33
|
+
Requires-Dist: pytest; extra == "test"
|
|
34
|
+
Requires-Dist: pytest-mock; extra == "test"
|
|
35
|
+
Dynamic: author
|
|
36
|
+
Dynamic: author-email
|
|
37
|
+
Dynamic: classifier
|
|
38
|
+
Dynamic: description
|
|
39
|
+
Dynamic: description-content-type
|
|
40
|
+
Dynamic: home-page
|
|
41
|
+
Dynamic: keywords
|
|
42
|
+
Dynamic: license
|
|
43
|
+
Dynamic: license-file
|
|
44
|
+
Dynamic: provides-extra
|
|
45
|
+
Dynamic: requires-dist
|
|
46
|
+
Dynamic: summary
|
|
29
47
|
|
|
30
48
|
|
|
31
49
|
**Status:**
|
|
@@ -39,10 +57,11 @@ A rainy weekends project under occasional development :)
|
|
|
39
57
|
- latest from source repository: `$ pip install git+https://github.com/akpw/batch-mp-tools.git`
|
|
40
58
|
|
|
41
59
|
#### Blogs:
|
|
42
|
-
- [Practical BatchMP](
|
|
43
|
-
- [
|
|
44
|
-
- [
|
|
45
|
-
- [
|
|
60
|
+
- [Practical BatchMP](https://akpw.github.io//tags.html#BatchMP+Tools)
|
|
61
|
+
- [Renamer Organize & Virtual Views](https://akpw.github.io/articles/2025/09/22/Print-and-Organize.html)
|
|
62
|
+
- [BatchMP Tools Tutorial](https://akpw.github.io//articles/2015/04/10/batchmp-tutorial-part-i.html)
|
|
63
|
+
- [The BatchMP Tools Project](https://akpw.github.io//articles/2015/03/21/the-batchmp-project.html)
|
|
64
|
+
- [Parallel batch media processing with FFmpeg and Python](https://akpw.github.io//articles/2014/11/24/batch-media-processing-ffmpeg-python.html)
|
|
46
65
|
|
|
47
66
|
## Description
|
|
48
67
|
|
|
@@ -62,7 +81,7 @@ By default the tools always visualize targeted changes (whenever possible) befor
|
|
|
62
81
|
|
|
63
82
|
A little bit more details on each utility:
|
|
64
83
|
|
|
65
|
-
[**Renamer**](https://github.com/akpw/batch-mp-tools#renamer) is a multi-platform batch rename tool. In addition to common operations such as regexp-based replace, adding text / dates, etc. it also supports advanced operations such as expandable template processing during replace, multi-level indexing across nested directories, flattening folders,
|
|
84
|
+
[**Renamer**](https://github.com/akpw/batch-mp-tools#renamer) is a multi-platform batch rename tool. In addition to common operations such as regexp-based replace, adding text / dates, etc. it also supports advanced operations such as expandable template processing during replace, multi-level indexing across nested directories, flattening folders, organizing files by type or date, etc. The enhanced print command now supports virtual views to preview organization without moving files.
|
|
66
85
|
At its simplest, Renamer can be used to print out the content of current directory:
|
|
67
86
|
```
|
|
68
87
|
$ renamer
|
|
@@ -91,6 +110,37 @@ For multi-level indexing of all M4A files in all sub-directories of the current
|
|
|
91
110
|
```
|
|
92
111
|
Sequential indexing is supported as well using the `-sq` switch. An important detail here, by default Renamer is visualizing the targeted changes and asking for permission to proceed before actually doing anything.
|
|
93
112
|
|
|
113
|
+
For organizing files by media type:
|
|
114
|
+
```
|
|
115
|
+
$ renamer organize -b type
|
|
116
|
+
~/Downloads
|
|
117
|
+
|- image/
|
|
118
|
+
|- photo1.jpg
|
|
119
|
+
|- screenshot.png
|
|
120
|
+
|- video/
|
|
121
|
+
|- movie.mp4
|
|
122
|
+
|- audio/
|
|
123
|
+
|- song.mp3
|
|
124
|
+
|
|
125
|
+
Proceed? [y/n]:
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
Or preview how files would look organized by date without moving them:
|
|
129
|
+
```
|
|
130
|
+
$ renamer print -b date --date-format "%Y/%m"
|
|
131
|
+
Virtual view by date:
|
|
132
|
+
~/Downloads
|
|
133
|
+
|- 2025/
|
|
134
|
+
|- 01/
|
|
135
|
+
|- document.pdf
|
|
136
|
+
|- photo.jpg
|
|
137
|
+
|- 02/
|
|
138
|
+
|- video.mp4
|
|
139
|
+
```
|
|
140
|
+
For more detailed examples and advanced organize / virtual views functionality, see:
|
|
141
|
+
- [Renamer Organize & Virtual Views](https://akpw.github.io/articles/2025/09/22/Print-and-Organize.html)
|
|
142
|
+
- [BatchMP Tools Tutorial, Part II: renaming files with renamer](https://akpw.github.io/articles/2015/04/11/batchmp-tutorial-part-ii.html)
|
|
143
|
+
- Other related posts in [Practical BatchMP](https://akpw.github.io//tags.html#BatchMP+Tools)
|
|
94
144
|
|
|
95
145
|
|
|
96
146
|
[**Tagger**](https://github.com/akpw/batch-mp-tools#tagger) manages media metadata, such as tags and artwork. Setting those in selected media file over multiple nested directories now becomes a breeze, with just a few simple commands working uniformly over almost any practically imaginable audio / video media formats. While easy to use, Tagger supports advanced metadata manipulation such as regexp-based replace, expandable template processing, etc. For example, to set the title tag to respective file names followed by the values of track and tracktotal tags:
|
|
@@ -117,6 +167,11 @@ Sequential indexing is supported as well using the `-sq` switch. An important d
|
|
|
117
167
|
```
|
|
118
168
|
The commands above show some of the available global options: `-r` for recursion into nested folders and `-in` to select media files. In the example above just one file was selected (for the sake of output brevity), which also could be achived via using `-f` for the file source mode.
|
|
119
169
|
|
|
170
|
+
For more practical examples, see:
|
|
171
|
+
- [BatchMP Tools Tutorial Part III: setting tags and artwork with tagger](https://akpw.github.io/articles/2015/04/12/batchmp-tutorial-part-iii.html)
|
|
172
|
+
- Other related posts in [Practical BatchMP](https://akpw.github.io//tags.html#BatchMP+Tools)
|
|
173
|
+
|
|
174
|
+
|
|
120
175
|
|
|
121
176
|
[**BMFP**](https://github.com/akpw/batch-mp-tools/blob/master/README.md#bmfp-requires-ffmpeg) is all about efficient media content processing, such as conversion between various formats, normalizing sound volume, segmenting / fragmenting media files, denoising audio, detaching individual audio / video streams, etc. As processing media files can typically be resource consuming, BMFP is designed to take advantage of multi-core processors. By default, it automatically breaks up jobs into individual tasks that are then run as separate processes on available CPU cores.
|
|
122
177
|
**BMFP is built on top of [FFmpeg](http://ffmpeg.org/download.html), which needs to be installed and available in the command line**. BMFP can be thought of as a batch FFmpeg runner, intended to make common uses of FFmpeg easy while not restricting its full power.
|
|
@@ -164,7 +219,10 @@ To check on the result, lets's just use the [tagger's](https://github.com/akpw/b
|
|
|
164
219
|
```
|
|
165
220
|
From a brief glance, all looks OK. BMFP used FFmpeg to do the actual conversion, while taking care of all other things like preserving tags / artwork, etc.
|
|
166
221
|
|
|
167
|
-
|
|
222
|
+
For more practical examples, see:
|
|
223
|
+
- [BatchMP Tools Tutorial, splitting a long media file with bmfp](https://akpw.github.io/articles/2015/04/10/batchmp-tutorial-part-i.html)
|
|
224
|
+
- Other related posts in [Practical BatchMP](https://akpw.github.io//tags.html#BatchMP+Tools)
|
|
225
|
+
|
|
168
226
|
|
|
169
227
|
|
|
170
228
|
## Brief Description of CLI Commands (use -h to expand on details for individual commands)
|
|
@@ -178,7 +236,9 @@ I will follow up with more examples and common use-cases in future blogs.
|
|
|
178
236
|
. display sorting:
|
|
179
237
|
.. by size/date, ascending/descending
|
|
180
238
|
. action commands:
|
|
181
|
-
.. print Prints source directory
|
|
239
|
+
.. print Prints source directory. Enhanced with virtual organization views:
|
|
240
|
+
$ renamer print -b type # Preview organize by media type
|
|
241
|
+
$ renamer print -b date -df "%Y/%m" # Preview organize by date
|
|
182
242
|
.. flatten Flatten all folders below target level, moving the
|
|
183
243
|
files up at the target level. By default, deletes all empty flattened folders
|
|
184
244
|
.. index Adds index to files and directories names
|
|
@@ -191,6 +251,10 @@ I will follow up with more examples and common use-cases in future blogs.
|
|
|
191
251
|
.. remove Removes n characters from files and directories names
|
|
192
252
|
.. capitalize Capitalizes words in files / directories names
|
|
193
253
|
.. delete Delete selected files and directories
|
|
254
|
+
.. organize Organizes files into subdirectories based on their attributes:
|
|
255
|
+
$ renamer organize -b type # By media type (image/, video/, audio/)
|
|
256
|
+
$ renamer organize -b date -df "%Y-%m" # By date (2025-01/, 2025-02/)
|
|
257
|
+
$ renamer organize -b date -df "%Y/%m" -td ~/Sorted # To target directory
|
|
194
258
|
|
|
195
259
|
Usage: renamer [-h] [-d DIR] [-f FILE] [Global Options] {Commands} [Commands Options]
|
|
196
260
|
Global Options:
|
|
@@ -215,7 +279,7 @@ I will follow up with more examples and common use-cases in future blogs.
|
|
|
215
279
|
[-q, --quiet] Do not visualise changes / show messages during processing
|
|
216
280
|
|
|
217
281
|
Commands:
|
|
218
|
-
{print, index, add_date, add_text, remove, replace, capitalize, flatten, delete, version, info}
|
|
282
|
+
{print, index, add_date, add_text, remove, replace, capitalize, flatten, delete, organize, version, info}
|
|
219
283
|
$ renamer {command} -h #run this for detailed help on individual commands
|
|
220
284
|
|
|
221
285
|
### tagger
|
|
@@ -324,7 +388,7 @@ Support via FFmpeg: 'AVI', 'FLV', 'MKV', 'MKA'
|
|
|
324
388
|
(shows hidden files excluded by default)
|
|
325
389
|
|
|
326
390
|
Target output Directory Target output directory. When omitted, will be
|
|
327
|
-
[-td, --target-dir] automatically created
|
|
391
|
+
[-td, --target-dir] automatically created inside the parent level of
|
|
328
392
|
the input source. For recursive processing,
|
|
329
393
|
the processed files directory structure there
|
|
330
394
|
will be the same as for the original files.
|
|
@@ -346,10 +410,38 @@ Support via FFmpeg: 'AVI', 'FLV', 'MKV', 'MKA'
|
|
|
346
410
|
|
|
347
411
|
|
|
348
412
|
## Installing Development version
|
|
349
|
-
- Clone the repo,
|
|
413
|
+
- Clone the repo, create a virtual environment, and activate it:
|
|
414
|
+
```bash
|
|
415
|
+
$ python3 -m venv .venv
|
|
416
|
+
$ source .venv/bin/activate
|
|
417
|
+
```
|
|
418
|
+
- Install the project in editable mode:
|
|
419
|
+
```bash
|
|
420
|
+
$ pip install -e .
|
|
421
|
+
```
|
|
422
|
+
|
|
423
|
+
## Running Tests
|
|
424
|
+
|
|
425
|
+
To run the test suite, first ensure you have installed the development dependencies:
|
|
426
|
+
```bash
|
|
427
|
+
$ pip install -e ".[test]"
|
|
428
|
+
```
|
|
350
429
|
|
|
351
|
-
**
|
|
352
|
-
|
|
430
|
+
**Using pytest (recommended):**
|
|
431
|
+
```bash
|
|
432
|
+
$ pytest -v --tb=short # Run all tests with verbose output
|
|
433
|
+
$ pytest tests/ # Run all tests
|
|
434
|
+
$ pytest tests/fs/test_fs_organize.py # Test organize functionality
|
|
435
|
+
$ pytest tests/fs/test_fsutils.py # Test core filesystem utilities
|
|
436
|
+
$ pytest tests/cli/test_renamer_cli.py # Test renamer CLI
|
|
437
|
+
$ pytest -k "test_organize" # Run tests matching pattern
|
|
438
|
+
```
|
|
439
|
+
|
|
440
|
+
**Using unittest (fallback):**
|
|
441
|
+
```bash
|
|
442
|
+
$ python -m unittest discover tests -v # Run all tests with verbose output
|
|
443
|
+
$ python -m unittest tests.fs.test_fs_organize # Run specific test module
|
|
444
|
+
```
|
|
353
445
|
|
|
354
446
|
|
|
355
447
|
|
|
@@ -1,32 +1,3 @@
|
|
|
1
|
-
Metadata-Version: 2.1
|
|
2
|
-
Name: batchmp
|
|
3
|
-
Version: 1.0
|
|
4
|
-
Summary: Command-line tools for batch media processing
|
|
5
|
-
Home-page: https://github.com/akpw/batch-mp-tools
|
|
6
|
-
Author: Arseniy Kuznetsov
|
|
7
|
-
Author-email: k.arseniy@gmail.com
|
|
8
|
-
License: GNU General Public License v2 (GPLv2)
|
|
9
|
-
Keywords: batch processing media video audio CLI rename tags ID3
|
|
10
|
-
Classifier: Development Status :: 4 - Beta
|
|
11
|
-
Classifier: License :: OSI Approved :: GNU General Public License v2 or later (GPLv2+)
|
|
12
|
-
Classifier: Programming Language :: Python
|
|
13
|
-
Classifier: Programming Language :: Python :: 3.6
|
|
14
|
-
Classifier: Programming Language :: Python :: 3 :: Only
|
|
15
|
-
Classifier: Intended Audience :: End Users/Desktop
|
|
16
|
-
Classifier: Intended Audience :: Developers
|
|
17
|
-
Classifier: Intended Audience :: System Administrators
|
|
18
|
-
Classifier: Intended Audience :: Information Technology
|
|
19
|
-
Classifier: Operating System :: OS Independent
|
|
20
|
-
Classifier: Topic :: Multimedia :: Sound/Audio
|
|
21
|
-
Classifier: Topic :: Multimedia :: Sound/Audio :: Analysis
|
|
22
|
-
Classifier: Topic :: Multimedia :: Sound/Audio :: Conversion
|
|
23
|
-
Classifier: Topic :: Multimedia :: Video
|
|
24
|
-
Classifier: Topic :: Multimedia :: Video :: Conversion
|
|
25
|
-
Classifier: Topic :: Software Development :: Libraries
|
|
26
|
-
Classifier: Topic :: Utilities
|
|
27
|
-
Description-Content-Type: text/markdown
|
|
28
|
-
License-File: LICENSE
|
|
29
|
-
|
|
30
1
|
|
|
31
2
|
**Status:**
|
|
32
3
|
A rainy weekends project under occasional development :)
|
|
@@ -39,10 +10,11 @@ A rainy weekends project under occasional development :)
|
|
|
39
10
|
- latest from source repository: `$ pip install git+https://github.com/akpw/batch-mp-tools.git`
|
|
40
11
|
|
|
41
12
|
#### Blogs:
|
|
42
|
-
- [Practical BatchMP](
|
|
43
|
-
- [
|
|
44
|
-
- [
|
|
45
|
-
- [
|
|
13
|
+
- [Practical BatchMP](https://akpw.github.io//tags.html#BatchMP+Tools)
|
|
14
|
+
- [Renamer Organize & Virtual Views](https://akpw.github.io/articles/2025/09/22/Print-and-Organize.html)
|
|
15
|
+
- [BatchMP Tools Tutorial](https://akpw.github.io//articles/2015/04/10/batchmp-tutorial-part-i.html)
|
|
16
|
+
- [The BatchMP Tools Project](https://akpw.github.io//articles/2015/03/21/the-batchmp-project.html)
|
|
17
|
+
- [Parallel batch media processing with FFmpeg and Python](https://akpw.github.io//articles/2014/11/24/batch-media-processing-ffmpeg-python.html)
|
|
46
18
|
|
|
47
19
|
## Description
|
|
48
20
|
|
|
@@ -62,7 +34,7 @@ By default the tools always visualize targeted changes (whenever possible) befor
|
|
|
62
34
|
|
|
63
35
|
A little bit more details on each utility:
|
|
64
36
|
|
|
65
|
-
[**Renamer**](https://github.com/akpw/batch-mp-tools#renamer) is a multi-platform batch rename tool. In addition to common operations such as regexp-based replace, adding text / dates, etc. it also supports advanced operations such as expandable template processing during replace, multi-level indexing across nested directories, flattening folders,
|
|
37
|
+
[**Renamer**](https://github.com/akpw/batch-mp-tools#renamer) is a multi-platform batch rename tool. In addition to common operations such as regexp-based replace, adding text / dates, etc. it also supports advanced operations such as expandable template processing during replace, multi-level indexing across nested directories, flattening folders, organizing files by type or date, etc. The enhanced print command now supports virtual views to preview organization without moving files.
|
|
66
38
|
At its simplest, Renamer can be used to print out the content of current directory:
|
|
67
39
|
```
|
|
68
40
|
$ renamer
|
|
@@ -91,6 +63,37 @@ For multi-level indexing of all M4A files in all sub-directories of the current
|
|
|
91
63
|
```
|
|
92
64
|
Sequential indexing is supported as well using the `-sq` switch. An important detail here, by default Renamer is visualizing the targeted changes and asking for permission to proceed before actually doing anything.
|
|
93
65
|
|
|
66
|
+
For organizing files by media type:
|
|
67
|
+
```
|
|
68
|
+
$ renamer organize -b type
|
|
69
|
+
~/Downloads
|
|
70
|
+
|- image/
|
|
71
|
+
|- photo1.jpg
|
|
72
|
+
|- screenshot.png
|
|
73
|
+
|- video/
|
|
74
|
+
|- movie.mp4
|
|
75
|
+
|- audio/
|
|
76
|
+
|- song.mp3
|
|
77
|
+
|
|
78
|
+
Proceed? [y/n]:
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
Or preview how files would look organized by date without moving them:
|
|
82
|
+
```
|
|
83
|
+
$ renamer print -b date --date-format "%Y/%m"
|
|
84
|
+
Virtual view by date:
|
|
85
|
+
~/Downloads
|
|
86
|
+
|- 2025/
|
|
87
|
+
|- 01/
|
|
88
|
+
|- document.pdf
|
|
89
|
+
|- photo.jpg
|
|
90
|
+
|- 02/
|
|
91
|
+
|- video.mp4
|
|
92
|
+
```
|
|
93
|
+
For more detailed examples and advanced organize / virtual views functionality, see:
|
|
94
|
+
- [Renamer Organize & Virtual Views](https://akpw.github.io/articles/2025/09/22/Print-and-Organize.html)
|
|
95
|
+
- [BatchMP Tools Tutorial, Part II: renaming files with renamer](https://akpw.github.io/articles/2015/04/11/batchmp-tutorial-part-ii.html)
|
|
96
|
+
- Other related posts in [Practical BatchMP](https://akpw.github.io//tags.html#BatchMP+Tools)
|
|
94
97
|
|
|
95
98
|
|
|
96
99
|
[**Tagger**](https://github.com/akpw/batch-mp-tools#tagger) manages media metadata, such as tags and artwork. Setting those in selected media file over multiple nested directories now becomes a breeze, with just a few simple commands working uniformly over almost any practically imaginable audio / video media formats. While easy to use, Tagger supports advanced metadata manipulation such as regexp-based replace, expandable template processing, etc. For example, to set the title tag to respective file names followed by the values of track and tracktotal tags:
|
|
@@ -117,6 +120,11 @@ Sequential indexing is supported as well using the `-sq` switch. An important d
|
|
|
117
120
|
```
|
|
118
121
|
The commands above show some of the available global options: `-r` for recursion into nested folders and `-in` to select media files. In the example above just one file was selected (for the sake of output brevity), which also could be achived via using `-f` for the file source mode.
|
|
119
122
|
|
|
123
|
+
For more practical examples, see:
|
|
124
|
+
- [BatchMP Tools Tutorial Part III: setting tags and artwork with tagger](https://akpw.github.io/articles/2015/04/12/batchmp-tutorial-part-iii.html)
|
|
125
|
+
- Other related posts in [Practical BatchMP](https://akpw.github.io//tags.html#BatchMP+Tools)
|
|
126
|
+
|
|
127
|
+
|
|
120
128
|
|
|
121
129
|
[**BMFP**](https://github.com/akpw/batch-mp-tools/blob/master/README.md#bmfp-requires-ffmpeg) is all about efficient media content processing, such as conversion between various formats, normalizing sound volume, segmenting / fragmenting media files, denoising audio, detaching individual audio / video streams, etc. As processing media files can typically be resource consuming, BMFP is designed to take advantage of multi-core processors. By default, it automatically breaks up jobs into individual tasks that are then run as separate processes on available CPU cores.
|
|
122
130
|
**BMFP is built on top of [FFmpeg](http://ffmpeg.org/download.html), which needs to be installed and available in the command line**. BMFP can be thought of as a batch FFmpeg runner, intended to make common uses of FFmpeg easy while not restricting its full power.
|
|
@@ -164,7 +172,10 @@ To check on the result, lets's just use the [tagger's](https://github.com/akpw/b
|
|
|
164
172
|
```
|
|
165
173
|
From a brief glance, all looks OK. BMFP used FFmpeg to do the actual conversion, while taking care of all other things like preserving tags / artwork, etc.
|
|
166
174
|
|
|
167
|
-
|
|
175
|
+
For more practical examples, see:
|
|
176
|
+
- [BatchMP Tools Tutorial, splitting a long media file with bmfp](https://akpw.github.io/articles/2015/04/10/batchmp-tutorial-part-i.html)
|
|
177
|
+
- Other related posts in [Practical BatchMP](https://akpw.github.io//tags.html#BatchMP+Tools)
|
|
178
|
+
|
|
168
179
|
|
|
169
180
|
|
|
170
181
|
## Brief Description of CLI Commands (use -h to expand on details for individual commands)
|
|
@@ -178,7 +189,9 @@ I will follow up with more examples and common use-cases in future blogs.
|
|
|
178
189
|
. display sorting:
|
|
179
190
|
.. by size/date, ascending/descending
|
|
180
191
|
. action commands:
|
|
181
|
-
.. print Prints source directory
|
|
192
|
+
.. print Prints source directory. Enhanced with virtual organization views:
|
|
193
|
+
$ renamer print -b type # Preview organize by media type
|
|
194
|
+
$ renamer print -b date -df "%Y/%m" # Preview organize by date
|
|
182
195
|
.. flatten Flatten all folders below target level, moving the
|
|
183
196
|
files up at the target level. By default, deletes all empty flattened folders
|
|
184
197
|
.. index Adds index to files and directories names
|
|
@@ -191,6 +204,10 @@ I will follow up with more examples and common use-cases in future blogs.
|
|
|
191
204
|
.. remove Removes n characters from files and directories names
|
|
192
205
|
.. capitalize Capitalizes words in files / directories names
|
|
193
206
|
.. delete Delete selected files and directories
|
|
207
|
+
.. organize Organizes files into subdirectories based on their attributes:
|
|
208
|
+
$ renamer organize -b type # By media type (image/, video/, audio/)
|
|
209
|
+
$ renamer organize -b date -df "%Y-%m" # By date (2025-01/, 2025-02/)
|
|
210
|
+
$ renamer organize -b date -df "%Y/%m" -td ~/Sorted # To target directory
|
|
194
211
|
|
|
195
212
|
Usage: renamer [-h] [-d DIR] [-f FILE] [Global Options] {Commands} [Commands Options]
|
|
196
213
|
Global Options:
|
|
@@ -215,7 +232,7 @@ I will follow up with more examples and common use-cases in future blogs.
|
|
|
215
232
|
[-q, --quiet] Do not visualise changes / show messages during processing
|
|
216
233
|
|
|
217
234
|
Commands:
|
|
218
|
-
{print, index, add_date, add_text, remove, replace, capitalize, flatten, delete, version, info}
|
|
235
|
+
{print, index, add_date, add_text, remove, replace, capitalize, flatten, delete, organize, version, info}
|
|
219
236
|
$ renamer {command} -h #run this for detailed help on individual commands
|
|
220
237
|
|
|
221
238
|
### tagger
|
|
@@ -324,7 +341,7 @@ Support via FFmpeg: 'AVI', 'FLV', 'MKV', 'MKA'
|
|
|
324
341
|
(shows hidden files excluded by default)
|
|
325
342
|
|
|
326
343
|
Target output Directory Target output directory. When omitted, will be
|
|
327
|
-
[-td, --target-dir] automatically created
|
|
344
|
+
[-td, --target-dir] automatically created inside the parent level of
|
|
328
345
|
the input source. For recursive processing,
|
|
329
346
|
the processed files directory structure there
|
|
330
347
|
will be the same as for the original files.
|
|
@@ -346,10 +363,38 @@ Support via FFmpeg: 'AVI', 'FLV', 'MKV', 'MKA'
|
|
|
346
363
|
|
|
347
364
|
|
|
348
365
|
## Installing Development version
|
|
349
|
-
- Clone the repo,
|
|
366
|
+
- Clone the repo, create a virtual environment, and activate it:
|
|
367
|
+
```bash
|
|
368
|
+
$ python3 -m venv .venv
|
|
369
|
+
$ source .venv/bin/activate
|
|
370
|
+
```
|
|
371
|
+
- Install the project in editable mode:
|
|
372
|
+
```bash
|
|
373
|
+
$ pip install -e .
|
|
374
|
+
```
|
|
375
|
+
|
|
376
|
+
## Running Tests
|
|
377
|
+
|
|
378
|
+
To run the test suite, first ensure you have installed the development dependencies:
|
|
379
|
+
```bash
|
|
380
|
+
$ pip install -e ".[test]"
|
|
381
|
+
```
|
|
350
382
|
|
|
351
|
-
**
|
|
352
|
-
|
|
383
|
+
**Using pytest (recommended):**
|
|
384
|
+
```bash
|
|
385
|
+
$ pytest -v --tb=short # Run all tests with verbose output
|
|
386
|
+
$ pytest tests/ # Run all tests
|
|
387
|
+
$ pytest tests/fs/test_fs_organize.py # Test organize functionality
|
|
388
|
+
$ pytest tests/fs/test_fsutils.py # Test core filesystem utilities
|
|
389
|
+
$ pytest tests/cli/test_renamer_cli.py # Test renamer CLI
|
|
390
|
+
$ pytest -k "test_organize" # Run tests matching pattern
|
|
391
|
+
```
|
|
392
|
+
|
|
393
|
+
**Using unittest (fallback):**
|
|
394
|
+
```bash
|
|
395
|
+
$ python -m unittest discover tests -v # Run all tests with verbose output
|
|
396
|
+
$ python -m unittest tests.fs.test_fs_organize # Run specific test module
|
|
397
|
+
```
|
|
353
398
|
|
|
354
399
|
|
|
355
400
|
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
13
13
|
## GNU General Public License for more details.
|
|
14
14
|
|
|
15
|
-
import
|
|
15
|
+
from importlib import metadata
|
|
16
16
|
import batchmp.cli.base.vchk
|
|
17
17
|
from batchmp.cli.base.bmp_options import BatchMPArgParser, BatchMPBaseCommands
|
|
18
18
|
|
|
@@ -43,7 +43,7 @@ class BatchMPDispatcher:
|
|
|
43
43
|
def print_version(self):
|
|
44
44
|
''' Prints BatchMP version info
|
|
45
45
|
'''
|
|
46
|
-
version =
|
|
46
|
+
version = metadata.version("batchmp")
|
|
47
47
|
print('BatchMP tools version {}'.format(version))
|
|
48
48
|
|
|
49
49
|
def print_info(self):
|
|
@@ -31,7 +31,7 @@
|
|
|
31
31
|
|
|
32
32
|
import os, sys, string
|
|
33
33
|
from argparse import ArgumentParser, HelpFormatter
|
|
34
|
-
from
|
|
34
|
+
from batchmp.commons.utils import strtobool
|
|
35
35
|
from urllib.parse import urlparse
|
|
36
36
|
from batchmp.commons.utils import MiscHelpers
|
|
37
37
|
from batchmp.fstools.fsutils import FSH
|
|
@@ -94,7 +94,9 @@ class BMFPDispatcher(BatchMPDispatcher):
|
|
|
94
94
|
ff_entry_params = FFEntryParamsExt(args)
|
|
95
95
|
Fragmenter().fragment(ff_entry_params,
|
|
96
96
|
fragment_starttime = args['fragment_starttime'].total_seconds(),
|
|
97
|
-
fragment_duration = args['fragment_duration'].total_seconds()
|
|
97
|
+
fragment_duration = args['fragment_duration'].total_seconds(),
|
|
98
|
+
fragment_trim = args['fragment_trim'].total_seconds(),
|
|
99
|
+
)
|
|
98
100
|
|
|
99
101
|
def segment(self, args):
|
|
100
102
|
ff_entry_params = FFEntryParamsExt(args)
|
|
@@ -146,8 +146,9 @@ class BMFPArgParser(BatchMPArgParser):
|
|
|
146
146
|
target_output_group = parser.add_argument_group('Target Output Directory')
|
|
147
147
|
target_output_group.add_argument("-td", "--target-dir", dest = "target_dir",
|
|
148
148
|
type = lambda d: self._is_valid_dir_path(parser, d),
|
|
149
|
+
default = '.',
|
|
149
150
|
help = "Target output directory. When omitted, will be automatically "
|
|
150
|
-
"created
|
|
151
|
+
"created inside the parent level of the input source. "
|
|
151
152
|
"For recursive processing, the processed files directory structure there "
|
|
152
153
|
"will be the same as for the original files.")
|
|
153
154
|
|
|
@@ -246,14 +247,18 @@ class BMFPArgParser(BatchMPArgParser):
|
|
|
246
247
|
description = 'Extracts a fragment via specified start time & duration',
|
|
247
248
|
formatter_class = BatchMPHelpFormatter)
|
|
248
249
|
group = fragment_parser.add_argument_group('Fragment parameters')
|
|
249
|
-
group.add_argument('-fs', '--
|
|
250
|
+
group.add_argument('-fs', '--start', dest='fragment_starttime',
|
|
250
251
|
help = 'Fragment start time, in seconds or in the "hh:mm:ss[.xxx]" format',
|
|
251
252
|
type = lambda f: self._is_timedelta(parser, f),
|
|
252
253
|
required = True)
|
|
253
254
|
group.add_argument('-fd', '--duration', dest='fragment_duration',
|
|
254
|
-
help = 'Fragment duration, in seconds or in the "hh:mm:ss[.xxx]" format',
|
|
255
|
+
help = 'Fragment duration (default is full media length), in seconds or in the "hh:mm:ss[.xxx]" format',
|
|
255
256
|
type = lambda f: self._is_timedelta(parser, f),
|
|
256
257
|
default = timedelta(days = 380))
|
|
258
|
+
group.add_argument('-ft', '--trim', dest='fragment_trim',
|
|
259
|
+
help = 'Fragment trimming at the end (optional), in seconds or in the "hh:mm:ss[.xxx]" format',
|
|
260
|
+
type = lambda f: self._is_timedelta(parser, f),
|
|
261
|
+
default = timedelta(0))
|
|
257
262
|
|
|
258
263
|
# Segment
|
|
259
264
|
segment_parser = subparsers.add_parser(BMFPCommands.SEGMENT,
|
|
@@ -16,7 +16,7 @@ from batchmp.cli.base.bmp_dispatch import BatchMPDispatcher
|
|
|
16
16
|
from batchmp.cli.renamer.renamer_options import RenameArgParser, RenamerCommands
|
|
17
17
|
from batchmp.fstools.dirtools import DHandler
|
|
18
18
|
from batchmp.fstools.rename import Renamer
|
|
19
|
-
from batchmp.fstools.builders.fsprms import FSEntryParamsBase, FSEntryParamsExt, FSEntryParamsFlatten
|
|
19
|
+
from batchmp.fstools.builders.fsprms import FSEntryParamsBase, FSEntryParamsExt, FSEntryParamsFlatten, FSEntryParamsOrganize
|
|
20
20
|
from batchmp.fstools.builders.fsb import FSEntryBuilderBase
|
|
21
21
|
|
|
22
22
|
class RenameDispatcher(BatchMPDispatcher):
|
|
@@ -61,6 +61,9 @@ class RenameDispatcher(BatchMPDispatcher):
|
|
|
61
61
|
elif args['sub_cmd'] == RenamerCommands.STATS:
|
|
62
62
|
self.stats(args)
|
|
63
63
|
|
|
64
|
+
elif args['sub_cmd'] == RenamerCommands.ORGANIZE:
|
|
65
|
+
self.organize(args)
|
|
66
|
+
|
|
64
67
|
else:
|
|
65
68
|
print('Nothing to dispatch')
|
|
66
69
|
return False
|
|
@@ -69,8 +72,13 @@ class RenameDispatcher(BatchMPDispatcher):
|
|
|
69
72
|
|
|
70
73
|
# Dispatched Methods
|
|
71
74
|
def print_dir(self, args):
|
|
72
|
-
|
|
73
|
-
|
|
75
|
+
# Check if organize view is requested
|
|
76
|
+
if args.get('by'):
|
|
77
|
+
fs_entry_params = FSEntryParamsOrganize(args)
|
|
78
|
+
DHandler.print_organized_view(fs_entry_params)
|
|
79
|
+
else:
|
|
80
|
+
fs_entry_params = FSEntryParamsBase(args)
|
|
81
|
+
DHandler.print_dir(fs_entry_params)
|
|
74
82
|
|
|
75
83
|
def stats(self, args):
|
|
76
84
|
fs_entry_params = FSEntryParamsBase(args)
|
|
@@ -117,7 +125,10 @@ class RenameDispatcher(BatchMPDispatcher):
|
|
|
117
125
|
fs_entry_params = FSEntryParamsExt(args)
|
|
118
126
|
Renamer.delete(fs_entry_params)
|
|
119
127
|
|
|
120
|
-
|
|
128
|
+
def organize(self, args):
|
|
129
|
+
fs_entry_params = FSEntryParamsOrganize(args)
|
|
130
|
+
DHandler.organize(fs_entry_params)
|
|
131
|
+
|
|
121
132
|
def main():
|
|
122
133
|
''' Renamer entry point
|
|
123
134
|
'''
|
|
@@ -74,6 +74,7 @@ class RenamerCommands(BatchMPBaseCommands):
|
|
|
74
74
|
FLATTEN = 'flatten'
|
|
75
75
|
DELETE = 'delete'
|
|
76
76
|
STATS = 'stats'
|
|
77
|
+
ORGANIZE = 'organize'
|
|
77
78
|
|
|
78
79
|
@classmethod
|
|
79
80
|
def commands_meta(cls):
|
|
@@ -89,7 +90,8 @@ class RenamerCommands(BatchMPBaseCommands):
|
|
|
89
90
|
'{}, '.format(cls.DELETE),
|
|
90
91
|
'{}, '.format(cls.STATS),
|
|
91
92
|
'{}, '.format(cls.INFO),
|
|
92
|
-
'{}'.format(cls.VERSION),
|
|
93
|
+
'{}, '.format(cls.VERSION),
|
|
94
|
+
'{}' .format(cls.ORGANIZE),
|
|
93
95
|
'}'))
|
|
94
96
|
|
|
95
97
|
|
|
@@ -142,6 +144,14 @@ class RenameArgParser(BatchMPArgParser):
|
|
|
142
144
|
print_parser.add_argument('-ss', '--show-size', dest = 'show_size',
|
|
143
145
|
help ='Show files size',
|
|
144
146
|
action = 'store_true')
|
|
147
|
+
print_parser.add_argument('-b', '--by', dest = 'by',
|
|
148
|
+
help = 'Show organized virtual view by type or date',
|
|
149
|
+
type = str,
|
|
150
|
+
choices = ['type', 'date'])
|
|
151
|
+
print_parser.add_argument('-df', '--date-format', dest = 'date_format',
|
|
152
|
+
help = 'Date format for subdirectories when using -b date (e.g., %%Y/%%m)',
|
|
153
|
+
type = str,
|
|
154
|
+
default = '%Y-%m-%d')
|
|
145
155
|
|
|
146
156
|
# Stats
|
|
147
157
|
stats_parser = subparsers.add_parser(RenamerCommands.STATS,
|
|
@@ -299,6 +309,27 @@ class RenameArgParser(BatchMPArgParser):
|
|
|
299
309
|
self._add_arg_display_curent_state_mode(delete_parser)
|
|
300
310
|
|
|
301
311
|
|
|
312
|
+
# Organize
|
|
313
|
+
organize_parser = subparsers.add_parser(RenamerCommands.ORGANIZE,
|
|
314
|
+
description='Organize selected files into directories by specified attributes',
|
|
315
|
+
formatter_class=BatchMPHelpFormatter)
|
|
316
|
+
organize_parser.add_argument('-b', '--by', dest='by',
|
|
317
|
+
help='Organization strategy: by type or by date',
|
|
318
|
+
type=str,
|
|
319
|
+
choices=['type', 'date'],
|
|
320
|
+
required=True)
|
|
321
|
+
organize_parser.add_argument('-df', '--date-format', dest='date_format',
|
|
322
|
+
help='Date format for subdirectories (e.g., %%Y/%%m)',
|
|
323
|
+
type=str,
|
|
324
|
+
default='%Y-%m-%d')
|
|
325
|
+
organize_parser.add_argument('-td', '--target-dir', dest='target_dir',
|
|
326
|
+
help='Target directory to organize files into',
|
|
327
|
+
type=str)
|
|
328
|
+
_add_include_mode_group(organize_parser)
|
|
329
|
+
self._add_arg_display_curent_state_mode(organize_parser)
|
|
330
|
+
|
|
331
|
+
|
|
332
|
+
|
|
302
333
|
# Args Checking
|
|
303
334
|
def default_command(self, args, parser):
|
|
304
335
|
args['sub_cmd'] = RenamerCommands.PRINT
|
|
@@ -61,6 +61,16 @@ def run_cmd(cmd, shell = False):
|
|
|
61
61
|
return output
|
|
62
62
|
|
|
63
63
|
|
|
64
|
+
def strtobool(val):
|
|
65
|
+
val = str(val).lower()
|
|
66
|
+
if val in ('y', 'yes', 't', 'true', 'on', '1'):
|
|
67
|
+
return 1
|
|
68
|
+
elif val in ('n', 'no', 'f', 'false', 'off', '0'):
|
|
69
|
+
return 0
|
|
70
|
+
else:
|
|
71
|
+
raise ValueError("invalid truth value %r" % (val,))
|
|
72
|
+
|
|
73
|
+
|
|
64
74
|
class MiscHelpers:
|
|
65
75
|
@staticmethod
|
|
66
76
|
def int_num_digits(num):
|
|
@@ -99,7 +99,7 @@ class CueSplitterTask(ConvertorTask):
|
|
|
99
99
|
with temp_dir() as tmp_dir:
|
|
100
100
|
# prepare the tmp output path
|
|
101
101
|
conv_fname = '{0:02d} {1}'.format(self.track_number, self.track_title)
|
|
102
|
-
conv_fname = re.sub('[^\w\-_\. ]', '_', conv_fname)
|
|
102
|
+
conv_fname = re.sub(r'[^\w\-_\. ]', '_', conv_fname)
|
|
103
103
|
conv_fname = ''.join((conv_fname, self.target_format))
|
|
104
104
|
conv_fpath = os.path.join(tmp_dir, conv_fname)
|
|
105
105
|
|
|
@@ -198,12 +198,12 @@ class CueSplitter(FFMPRunner):
|
|
|
198
198
|
if cue_sheet.rem:
|
|
199
199
|
for rem_item in cue_sheet.rem:
|
|
200
200
|
if not tag_holder.year:
|
|
201
|
-
match = re.match('DATE.+(\d{4})', rem_item)
|
|
201
|
+
match = re.match(r'DATE.+(\d{4})', rem_item)
|
|
202
202
|
if match:
|
|
203
203
|
tag_holder.year = match.group(1)
|
|
204
204
|
continue
|
|
205
205
|
if not tag_holder.genre:
|
|
206
|
-
match = re.match('GENRE\s+(.+)$', rem_item)
|
|
206
|
+
match = re.match(r'GENRE\s+(.+)$', rem_item)
|
|
207
207
|
if match:
|
|
208
208
|
tag_holder.genre = match.group(1)
|
|
209
209
|
tag_holder.comments = ', '.join(cue_sheet.rem)
|