ripcd: Support ripping to Flac as well as Vorbis

master
Dustin 2016-07-10 17:30:29 -05:00
parent 27d13532ea
commit 8801b6433c
1 changed files with 53 additions and 11 deletions

View File

@ -100,7 +100,7 @@ class Track(object):
'Tracktitle': 'title', 'Tracktitle': 'title',
} }
FILENAME_FORMAT = '{tracknumber:0>2} {artist} - {title}.ogg' FILENAME_FORMAT = '{tracknumber:0>2} {artist} - {title}.{ext}'
def __init__(self): def __init__(self):
self.filename = None self.filename = None
@ -108,10 +108,13 @@ class Track(object):
@property @property
def outfile(self): def outfile(self):
if self.tags: if self.tags.get('title'):
return self.FILENAME_FORMAT.format(**self.tags) return self.FILENAME_FORMAT.format(ext=self.extension, **self.tags)
else: else:
return os.path.splitext(self.filename)[0] + '.ogg' return '{filename}.{ext}'.format(
filename=os.path.splitext(self.filename)[0],
ext=self.extension,
)
@classmethod @classmethod
def from_file(cls, filename): def from_file(cls, filename):
@ -145,13 +148,28 @@ class Track(object):
self.tags[tag] = titlecase(value.strip().strip("'")) self.tags[tag] = titlecase(value.strip().strip("'"))
@asyncio.coroutine @asyncio.coroutine
def to_vorbis(self, lock=None): def encode(self, lock=None):
assert self.filename assert self.filename
loop = asyncio.get_event_loop() loop = asyncio.get_event_loop()
yield from loop.run_in_executor(None, self._parse_inf) yield from loop.run_in_executor(None, self._parse_inf)
if lock: if lock:
yield from lock.acquire() yield from lock.acquire()
print('Encoding {} as {}'.format(self.filename, self.outfile)) print('Encoding {} as {}'.format(self.filename, self.outfile))
def write_tags(self):
tags = mutagen.File(self.outfile, easy=True)
tags.update(self.tags)
tags.save()
class VorbisTrack(Track):
extension = 'ogg'
@asyncio.coroutine
def encode(self, lock=None):
yield from super(VorbisTrack, self).encode(lock)
loop = asyncio.get_event_loop()
cmd = ['oggenc', '-q', '9', '-Q', '-o', self.outfile, self.filename] cmd = ['oggenc', '-q', '9', '-Q', '-o', self.outfile, self.filename]
p = yield from asyncio.create_subprocess_exec(*cmd) p = yield from asyncio.create_subprocess_exec(*cmd)
yield from p.wait() yield from p.wait()
@ -162,10 +180,24 @@ class Track(object):
if self.tags: if self.tags:
yield from loop.run_in_executor(None, self.write_tags) yield from loop.run_in_executor(None, self.write_tags)
def write_tags(self):
tags = mutagen.File(self.outfile, easy=True) class FlacTrack(Track):
tags.update(self.tags)
tags.save() extension = 'flac'
@asyncio.coroutine
def encode(self, lock=None):
yield from super(FlacTrack, self).encode(lock)
loop = asyncio.get_event_loop()
cmd = ['flac', '-s', '-o', self.outfile, self.filename]
p = yield from asyncio.create_subprocess_exec(*cmd)
yield from p.wait()
if p.returncode != 0:
sys.stderr.write('Failed to encode {}\n'.format(self.filename))
if lock:
lock.release()
if self.tags:
yield from loop.run_in_executor(None, self.write_tags)
@asyncio.coroutine @asyncio.coroutine
@ -222,13 +254,14 @@ def rip_info(device):
@asyncio.coroutine @asyncio.coroutine
def rip_tracks(device, num_encoders=None): def rip_tracks(device, codec, num_encoders=None):
if not num_encoders: if not num_encoders:
num_encoders = multiprocessing.cpu_count() num_encoders = multiprocessing.cpu_count()
cmd = ['icedax'] cmd = ['icedax']
if device: if device:
cmd.extend(('--device', device)) cmd.extend(('--device', device))
cmd.extend(( cmd.extend((
'--max',
'--alltracks', '--alltracks',
'--no-infofile', '--no-infofile',
'--verbose-level', 'summary', '--verbose-level', 'summary',
@ -242,7 +275,13 @@ def rip_tracks(device, num_encoders=None):
lock = asyncio.Semaphore(num_encoders) lock = asyncio.Semaphore(num_encoders)
tasks = [] tasks = []
for filename in glob.glob('*.wav'): for filename in glob.glob('*.wav'):
tasks.append(Track.from_file(filename).to_vorbis(lock)) if codec == 'vorbis':
track = VorbisTrack.from_file(filename)
elif codec == 'flac':
track = FlacTrack.from_file(filename)
else:
raise ValueError('Unsupported codec: {}'.format(codec))
tasks.append(track.encode(lock))
yield from asyncio.wait(tasks) yield from asyncio.wait(tasks)
@ -282,6 +321,9 @@ def parse_args():
parser.add_argument('--no-clean', dest='cleanup', action='store_false', parser.add_argument('--no-clean', dest='cleanup', action='store_false',
default=True, default=True,
help='Do not remove temporary files') help='Do not remove temporary files')
parser.add_argument('--codec', '-c', choices=('vorbis', 'flac'),
default='vorbis',
help='Encode audio with specific codec')
parser.add_argument('device', nargs='?', parser.add_argument('device', nargs='?',
help='CD-ROM device to use') help='CD-ROM device to use')
return parser.parse_args() return parser.parse_args()