mirror of
https://github.com/gryf/flac2ogg.git
synced 2026-10-16 12:22:30 +02:00
Compare commits
5
Commits
0dba6d7310
..
1.3
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7a671a5a6d | ||
|
|
5a45d56784 | ||
|
|
38dc4234e0 | ||
|
|
8fe2c53ce9 | ||
|
|
2b81619bfe |
No files matched your search
+14
-8
@@ -15,9 +15,10 @@ conversion between different type of audio formats.
|
||||
Requirements
|
||||
============
|
||||
|
||||
- python in version 2.7 or 3
|
||||
- python 3
|
||||
- `mutagen`_ python library for tag read/write
|
||||
- `vorbis tools`_ for ``ogg`` files encode/decode
|
||||
- `opus tools`_ for ``opus`` files encode/decode
|
||||
- `lame`_ for ``mp3`` files encode/decode
|
||||
- `flac`_ for ``flac`` files decode
|
||||
- `mac`_ for ``Monkey audio codecs``/``ape`` files decode
|
||||
@@ -37,16 +38,19 @@ Conversion can be performed from the following formats:
|
||||
- WavePack
|
||||
- Ape
|
||||
- Ogg Vorbis
|
||||
- Ogg Opus
|
||||
|
||||
Currently supported encoders:
|
||||
|
||||
- Ogg Vorbis
|
||||
- Ogg Opus
|
||||
- MP3 (lame)
|
||||
|
||||
There is an option to set the quality for the encoders - for *Ogg* files there
|
||||
would be used an ``-q`` option for ``oggenc`` command, and for the *mp3*
|
||||
format, ``-V`` option would be used for ``lame`` command. Consult corresponding
|
||||
man pages for details.
|
||||
There is an option to set the quality for the encoders - for *Vorbis* files
|
||||
there would be used an ``-q`` option for ``oggenc`` command, for the *mp3*
|
||||
format ``-V`` option would be used for ``lame`` command and ``--bitrate`` for
|
||||
``opusenc`` for the *Opus* files. Consult corresponding encoder man pages for
|
||||
details.
|
||||
|
||||
Usage
|
||||
=====
|
||||
@@ -57,9 +61,10 @@ Given that there are couple of music files, simplest usage is as follows:
|
||||
|
||||
$ flac2ogg.py directory_of_music_files/*
|
||||
|
||||
All files from that directory will be encoded to *ogg* by defaults. If there
|
||||
are already some *ogg* files, new files would have ``_encoded_`` added into the
|
||||
filename. Note, that output files will be placed next to the original files.
|
||||
All files from that directory will be encoded to *opus* by default. If there
|
||||
are already some *opus* files, new files would have ``_encoded_`` added into
|
||||
the filename. Note, that output files will be placed next to the original
|
||||
files.
|
||||
|
||||
License
|
||||
=======
|
||||
@@ -69,6 +74,7 @@ This work is licensed on 3-clause BSD license. See LICENSE file for details.
|
||||
|
||||
.. _mutagen: https://mutagen.readthedocs.io/en/latest/
|
||||
.. _vorbis tools: http://www.vorbis.com/
|
||||
.. _opus tools: https://opus-codec.org
|
||||
.. _flac: http://www.vorbis.com/
|
||||
.. _lame: http://lame.sourceforge.net/
|
||||
.. _mac: http://www.deb-multimedia.org/dists/testing/main/binary-amd64/package/monkeys-audio.php
|
||||
|
||||
+69
-32
@@ -14,18 +14,15 @@ from mutagen.mp3 import MP3
|
||||
from mutagen.easyid3 import EasyID3, EasyID3KeyError
|
||||
|
||||
|
||||
VERSION = '1.0'
|
||||
VERSION = '1.3'
|
||||
|
||||
|
||||
def match_file(path):
|
||||
"""Get all wav files from provided location"""
|
||||
matched_files = []
|
||||
re_ = re.compile(r"^.*_\d+.wav$")
|
||||
|
||||
for filename in os.listdir(os.path.abspath(path)):
|
||||
if re_.match(filename):
|
||||
matched_files.append(os.path.join(path, filename))
|
||||
|
||||
matched_files = [os.path.join(path, filename)
|
||||
for filename in os.listdir(os.path.abspath(path))
|
||||
if re_.match(filename)]
|
||||
return sorted(matched_files)
|
||||
|
||||
|
||||
@@ -52,14 +49,14 @@ def encode(obj):
|
||||
obj.encode()
|
||||
|
||||
|
||||
class CueTrack(object):
|
||||
class CueTrack:
|
||||
def __init__(self):
|
||||
"""Init"""
|
||||
self.performer = None
|
||||
self.title = None
|
||||
|
||||
|
||||
class CueObjectParser(object):
|
||||
class CueObjectParser:
|
||||
def __init__(self, cuefile):
|
||||
"""Init"""
|
||||
self.cuefile = cuefile
|
||||
@@ -108,7 +105,7 @@ class CueObjectParser(object):
|
||||
continue
|
||||
|
||||
|
||||
class Encoder(object):
|
||||
class Encoder:
|
||||
"""Encoder base class"""
|
||||
EXT = ".undefined"
|
||||
|
||||
@@ -118,7 +115,7 @@ class Encoder(object):
|
||||
|
||||
def encode(self, input_fname, output_fname):
|
||||
"""Encode file"""
|
||||
raise NotImplementedError()
|
||||
raise NotImplementedError
|
||||
|
||||
|
||||
class OggEncoder(Encoder):
|
||||
@@ -127,13 +124,13 @@ class OggEncoder(Encoder):
|
||||
|
||||
def __init__(self, quality=None):
|
||||
"""Init"""
|
||||
super(OggEncoder, self).__init__(quality)
|
||||
super().__init__(quality)
|
||||
if self.quality is None:
|
||||
self.quality = 8
|
||||
|
||||
def encode(self, input_fname, output_fname):
|
||||
sp.check_call(["oggenc", "-q%s" % self.quality, input_fname,
|
||||
'-o', output_fname])
|
||||
sp.check_call(["oggenc", f"-q{self.quality}", input_fname, '-o',
|
||||
output_fname])
|
||||
|
||||
|
||||
class Mp3Encoder(Encoder):
|
||||
@@ -142,16 +139,30 @@ class Mp3Encoder(Encoder):
|
||||
|
||||
def __init__(self, quality=None):
|
||||
"""Init"""
|
||||
super(Mp3Encoder, self).__init__(quality)
|
||||
super().__init__(quality)
|
||||
if self.quality is None:
|
||||
self.quality = 6
|
||||
|
||||
def encode(self, input_fname, output_fname):
|
||||
sp.check_call(["lame", "-V%s" % self.quality, input_fname,
|
||||
sp.check_call(["lame", f"-V{self.quality}", input_fname, output_fname])
|
||||
|
||||
|
||||
class OpusEncoder(Encoder):
|
||||
"""Opus encoder"""
|
||||
EXT = ".opus"
|
||||
|
||||
def __init__(self, quality=None):
|
||||
"""Init"""
|
||||
super().__init__(quality)
|
||||
if self.quality is None:
|
||||
self.quality = 128
|
||||
|
||||
def encode(self, input_fname, output_fname):
|
||||
sp.check_call(["opusenc", "--bitrate", self.quality, input_fname,
|
||||
output_fname])
|
||||
|
||||
|
||||
class FileType(object):
|
||||
class FileType:
|
||||
"""Base class for file objects"""
|
||||
extensions = {'ogg': '.ogg',
|
||||
'mp3': '.mp3'}
|
||||
@@ -175,7 +186,7 @@ class FileType(object):
|
||||
|
||||
def extract_wav(self):
|
||||
"""Dummy function for wav files"""
|
||||
raise NotImplementedError()
|
||||
raise NotImplementedError
|
||||
|
||||
def encode(self):
|
||||
"""Encode and tag file"""
|
||||
@@ -283,7 +294,7 @@ class M4aType(FileType):
|
||||
"""M4a filetype"""
|
||||
|
||||
def __init__(self, filename, encoder):
|
||||
super(M4aType, self).__init__(filename, encoder)
|
||||
super().__init__(filename, encoder)
|
||||
|
||||
def extract_wav(self):
|
||||
"""Extract m4a file to wav"""
|
||||
@@ -291,14 +302,14 @@ class M4aType(FileType):
|
||||
if "," in wav:
|
||||
wav = wav.replace(",", "\\,")
|
||||
sp.check_call(["mplayer", "-vo", "none", self.filename, "-ao",
|
||||
"pcm:file=%s" % wav])
|
||||
f"pcm:file={wav}"])
|
||||
|
||||
|
||||
class WavType(FileType):
|
||||
"""Uncompressed wav filetype"""
|
||||
|
||||
def __init__(self, filename, encoder):
|
||||
super(WavType, self).__init__(filename, encoder)
|
||||
super().__init__(filename, encoder)
|
||||
self.wav = filename
|
||||
self.tmp_wav_remove = False
|
||||
|
||||
@@ -315,21 +326,45 @@ class Mp3Type(FileType):
|
||||
sp.check_call(["lame", "--decode", self.filename, self.wav])
|
||||
|
||||
|
||||
class MusepackType(FileType):
|
||||
"""Musepack filetype"""
|
||||
|
||||
def __init__(self, filename, encoder):
|
||||
super().__init__(filename, encoder)
|
||||
|
||||
def extract_wav(self):
|
||||
"""Extract m4a file to wav"""
|
||||
wav = self.wav
|
||||
if "," in wav:
|
||||
wav = wav.replace(",", "\\,")
|
||||
sp.check_call(["mpcdec", self.filename, self.wav])
|
||||
|
||||
|
||||
class OggType(FileType):
|
||||
"""Ogg Vorbis filetype"""
|
||||
|
||||
def extract_wav(self):
|
||||
"""Extract mp3 file to wav"""
|
||||
"""Extract ogg vorbis file to wav"""
|
||||
sp.check_call(["oggdec", self.filename])
|
||||
|
||||
|
||||
class Converter(object):
|
||||
class OpusType(FileType):
|
||||
"""Opus filetype"""
|
||||
|
||||
def extract_wav(self):
|
||||
"""Extract opus file to wav"""
|
||||
sp.check_call(["opusdec", self.filename])
|
||||
|
||||
|
||||
class Converter:
|
||||
"""Main class for converting files"""
|
||||
extract_map = {'.ape': ApeType,
|
||||
'.flac': FlacType,
|
||||
'.m4a': M4aType,
|
||||
'.mp3': Mp3Type,
|
||||
'.mpc': MusepackType,
|
||||
'.ogg': OggType,
|
||||
'.opus': OpusType,
|
||||
'.wav': WavType,
|
||||
'.wv': WvType}
|
||||
|
||||
@@ -369,11 +404,11 @@ class Converter(object):
|
||||
base + ".wv.cue", base + ".ape.cue"):
|
||||
if os.path.exists(tmp):
|
||||
cuefile = tmp
|
||||
print("*** cuefile: %s" % cuefile)
|
||||
print(f"*** cuefile: {cuefile}")
|
||||
break
|
||||
|
||||
if cuefile is None:
|
||||
print("*** No cuefile found for `%s'" % filename)
|
||||
print(f"*** No cuefile found for `{filename}'")
|
||||
return
|
||||
|
||||
cue = CueObjectParser(cuefile)
|
||||
@@ -382,7 +417,7 @@ class Converter(object):
|
||||
# list of wavs to encode
|
||||
klass = Converter.extract_map.get(ext.lower())
|
||||
if not klass:
|
||||
print("*** Cannot find right converter for `%s'" % ext)
|
||||
print(f"*** Cannot find right converter for `{ext}'")
|
||||
return
|
||||
|
||||
fobj = klass(filename, encoder)
|
||||
@@ -413,7 +448,8 @@ class Converter(object):
|
||||
|
||||
|
||||
ENCODERS = {'ogg': OggEncoder,
|
||||
'mp3': Mp3Encoder}
|
||||
'mp3': Mp3Encoder,
|
||||
'opus': OpusEncoder}
|
||||
|
||||
|
||||
def main():
|
||||
@@ -424,12 +460,13 @@ def main():
|
||||
help='Split output file with provided *.cue file')
|
||||
arg.add_argument('-r', '--recursive', action='store_true',
|
||||
help='Do the files searching recursive')
|
||||
arg.add_argument('-e', '--encoder', default='ogg', type=str,
|
||||
choices=('ogg', 'mp3'), help='Encoder to use. Defaults '
|
||||
'to "ogg"')
|
||||
arg.add_argument('-e', '--encoder', default='opus', type=str,
|
||||
choices=('ogg', 'mp3', 'opus'),
|
||||
help='Encoder to use. Defaults to "opus"')
|
||||
arg.add_argument('-q', '--quality', help='Quality of the encoded file. '
|
||||
'Consult "lame" and "oggenc" for details. Defaults are '
|
||||
'6 for lame and 8 for oggenc.')
|
||||
'Consult "lame", "oggenc" and "opusenc" manuals for '
|
||||
'details. Defaults are -V6 for lame, -q8 for oggenc and '
|
||||
'--bitrate 128 for opusenc')
|
||||
arg.add_argument('-v', '--version', action='version',
|
||||
version='%(prog)s v' + VERSION,
|
||||
help='Display version and exit.')
|
||||
|
||||
Reference in new issue
Block a user