From 8801b6433cc92ca1691b34ac88faf812134c7251 Mon Sep 17 00:00:00 2001 From: "Dustin C. Hatch" Date: Sun, 10 Jul 2016 17:30:29 -0500 Subject: [PATCH] ripcd: Support ripping to Flac as well as Vorbis --- ripcd.py | 64 ++++++++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 53 insertions(+), 11 deletions(-) diff --git a/ripcd.py b/ripcd.py index 1b1190e..ba907d4 100755 --- a/ripcd.py +++ b/ripcd.py @@ -100,7 +100,7 @@ class Track(object): 'Tracktitle': 'title', } - FILENAME_FORMAT = '{tracknumber:0>2} {artist} - {title}.ogg' + FILENAME_FORMAT = '{tracknumber:0>2} {artist} - {title}.{ext}' def __init__(self): self.filename = None @@ -108,10 +108,13 @@ class Track(object): @property def outfile(self): - if self.tags: - return self.FILENAME_FORMAT.format(**self.tags) + if self.tags.get('title'): + return self.FILENAME_FORMAT.format(ext=self.extension, **self.tags) else: - return os.path.splitext(self.filename)[0] + '.ogg' + return '{filename}.{ext}'.format( + filename=os.path.splitext(self.filename)[0], + ext=self.extension, + ) @classmethod def from_file(cls, filename): @@ -145,13 +148,28 @@ class Track(object): self.tags[tag] = titlecase(value.strip().strip("'")) @asyncio.coroutine - def to_vorbis(self, lock=None): + def encode(self, lock=None): assert self.filename loop = asyncio.get_event_loop() yield from loop.run_in_executor(None, self._parse_inf) if lock: yield from lock.acquire() 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] p = yield from asyncio.create_subprocess_exec(*cmd) yield from p.wait() @@ -162,10 +180,24 @@ class Track(object): if self.tags: yield from loop.run_in_executor(None, self.write_tags) - def write_tags(self): - tags = mutagen.File(self.outfile, easy=True) - tags.update(self.tags) - tags.save() + +class FlacTrack(Track): + + 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 @@ -222,13 +254,14 @@ def rip_info(device): @asyncio.coroutine -def rip_tracks(device, num_encoders=None): +def rip_tracks(device, codec, num_encoders=None): if not num_encoders: num_encoders = multiprocessing.cpu_count() cmd = ['icedax'] if device: cmd.extend(('--device', device)) cmd.extend(( + '--max', '--alltracks', '--no-infofile', '--verbose-level', 'summary', @@ -242,7 +275,13 @@ def rip_tracks(device, num_encoders=None): lock = asyncio.Semaphore(num_encoders) tasks = [] 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) @@ -282,6 +321,9 @@ def parse_args(): parser.add_argument('--no-clean', dest='cleanup', action='store_false', default=True, 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='?', help='CD-ROM device to use') return parser.parse_args()