-
-
Save frabad/5e4505b9f6e6c0ffb29e4fdb5a05c76e to your computer and use it in GitHub Desktop.
CUE splitter using ffmpeg
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python | |
import os | |
import subprocess | |
import sys | |
if len(sys.argv) != 2: | |
sys.exit("Usage:\n\t%s <%s>" % (sys.argv[0], 'input_cuesheet')) | |
cuesheet_fname = sys.argv[1] | |
global_metadata = {} | |
media_fname = "" | |
tracks = [] | |
if not os.path.exists(cuesheet_fname): | |
sys.exit("Cuesheet '%s' was not found." % cuesheet_fname) | |
with open(cuesheet_fname) as f: | |
for line in f.readlines(): | |
line = line.strip('\n') | |
if line.startswith('REM GENRE '): | |
global_metadata['genre'] = ' '.join(line.split(' ')[2:]) | |
if line.startswith('REM DATE '): | |
global_metadata['date'] = ' '.join(line.split(' ')[2:]) | |
if line.startswith('PERFORMER '): | |
global_metadata['artist'] = ' '.join(line.split(' ')[1:]).replace('"', '') | |
if line.startswith('TITLE '): | |
global_metadata['album'] = ' '.join(line.split(' ')[1:]).replace('"', '') | |
if line.startswith('FILE '): | |
media_fname = ' '.join(line.split(' ')[1:-1]).replace('"', '') | |
if line.startswith(' TRACK '): | |
track = global_metadata.copy() | |
track['track'] = int(line.strip().split(' ')[1], 10) | |
tracks.append(track) | |
if line.startswith(' TITLE '): | |
tracks[-1]['title'] = ' '.join(line.strip().split(' ')[1:]).replace('"', '') | |
if line.startswith(' PERFORMER '): | |
tracks[-1]['artist'] = ' '.join(line.strip().split(' ')[1:]).replace('"', '') | |
if line.startswith(' INDEX 01 '): | |
t = list(map(int, ' '.join(line.strip().split(' ')[2:]).replace('"', '').split(':'))) | |
tracks[-1]['start'] = 60 * t[0] + t[1] + t[2] / 100.0 | |
if not os.path.exists(media_fname): | |
sys.exit("Media file '%s' referenced in cue sheet could not be found." % media_fname) | |
for i in range(len(tracks)): | |
if i != len(tracks) - 1: | |
tracks[i]['duration'] = tracks[i + 1]['start'] - tracks[i]['start'] | |
for track in tracks: | |
track_metadata = { | |
'artist': track['artist'], | |
'title': track['title'], | |
'album': track['album'], | |
'track': str(track['track']) + '/' + str(len(tracks)) | |
} | |
if 'genre' in track: | |
track_metadata['genre'] = track['genre'] | |
if 'date' in track: | |
track_metadata['date'] = track['date'] | |
cmd, args = ['ffmpeg'], [] | |
args.extend(['-i',media_fname]) | |
args.extend(['-c','copy']) | |
args.extend(['-ss','%.2d:%.2d:%.2d' % (track['start'] / 60 / 60, track['start'] / 60 % 60, int(track['start'] % 60))]) | |
if 'duration' in track: | |
args.extend(['-t','%.2d:%.2d:%.2d' % (track['duration'] / 60 / 60, track['duration'] / 60 % 60, int(track['duration'] % 60))]) | |
for (k, v) in list(track_metadata.items()): | |
args.extend(['-metadata','%s=%s' % (k, v) ]) | |
args.append('%.2d - %s - %s%s' % (track['track'], track['artist'], track['title'], os.path.splitext(media_fname)[1])) | |
cmd.extend(args) | |
subprocess.call(cmd) | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Line 18:
Maybe it would be better to allow users to choose a file encoding via an argument or add some auto detection. I got decoding exceptions from some of my cuesheets with non-UTF encodings like JIS.
Line 20:
You might want to consider adding the containing directory of the cuesheet to form a path rather than using the media filename directly. People may run this script from a different working directory than the one containing the cuesheet and the media file. In that case, the script wouldn't be able to find the media file with only its name. Something like this should be fine:
A command line argument can also be added to allow users to choose where their media files are. But I would say assuming the cuesheet and the media sit in the same directory should be okay, since that seems to be a convention for most media players.
Line 69:
:
on Windows). However, after some Googling it seems that Python has not provided a convenient way to escape these invalid names. I might try to come up with some platform-dependent regexes to handle these cases without introducing any 3rd party dependencies.I ended up changing as follows to address the first two points:
By the way, ffmpeg seems to have a 7-year bug tracked at https://trac.ffmpeg.org/ticket/4905 that produces split FLAC files with wrong durations. I have yet to find a way to circumvent this issue.