Skip to content

Instantly share code, notes, and snippets.

@OscarL
Forked from bancek/cue_to_mp3.py
Last active February 6, 2025 02:38
Show Gist options
  • Save OscarL/8b8d5e60e69b5d16d80bbf62c9e23ab7 to your computer and use it in GitHub Desktop.
Save OscarL/8b8d5e60e69b5d16d80bbf62c9e23ab7 to your computer and use it in GitHub Desktop.
CUE splitter using ffmpeg (to mp3)
# Changes over the original:
#
# + Support both Python 2 & 3.
# * fixed location of bitrate parameters.
# * Fixed track duration so it does't cuts tracks short, nor starts them early
# (Margin of error for .flac source files should at most be around +/- 0.013 secs).
# + Added pre_gap support.
cue_file = 'file.cue'
d = open(cue_file).read().splitlines()
general = {}
tracks = []
current_file = None
def index2seconds(line):
mm, ss, ff = list(map(int, ' '.join(line.strip().split(' ')[2:]).replace('"', '').split(':')))
return 60 * mm + ss + ff / 75.0 # each FF is 1/75 of a sec
def replace_chars(string, chars=r':\/|<>?*"', replacement='_'):
"""
Return `string` with any char in the `chars` replaced by `replacement`.
Defaults to replace problematic/invalid chars for filenames/paths.
"""
for c in string:
if c in chars:
string = string.replace(c, replacement)
return string
for line in d:
if line.startswith('REM GENRE '):
general['genre'] = ' '.join(line.split(' ')[2:])
if line.startswith('REM DATE '):
general['date'] = ' '.join(line.split(' ')[2:])
if line.startswith('PERFORMER '):
general['artist'] = ' '.join(line.split(' ')[1:]).replace('"', '')
if line.startswith('TITLE '):
general['album'] = ' '.join(line.split(' ')[1:]).replace('"', '')
if line.startswith('FILE '):
current_file = ' '.join(line.split(' ')[1:-1]).replace('"', '')
if line.startswith(' TRACK '):
track = general.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 00 '):
tracks[-1]['pre_gap'] = index2seconds(line)
if line.startswith(' INDEX 01 '):
tracks[-1]['start'] = index2seconds(line)
for i in range(len(tracks) - 1):
if 'pre_gap' in tracks[i + 1]:
tracks[i]['duration'] = tracks[i + 1]['pre_gap'] - tracks[i]['start']
else:
tracks[i]['duration'] = tracks[i + 1]['start'] - tracks[i]['start']
for track in tracks:
metadata = {
'artist': track['artist'],
'title': track['title'],
'album': track['album'],
'track': str(track['track']) + '/' + str(len(tracks))
}
if 'genre' in track:
metadata['genre'] = track['genre']
if 'date' in track:
metadata['date'] = track['date']
cmd = 'ffmpeg'
cmd += ' -i "%s"' % current_file
cmd += ' -b:a 320k'
cmd += ' -ss %.2d:%.2d:%09.6f' % (track['start'] / 60 / 60, track['start'] / 60 % 60, track['start'] % 60)
if 'duration' in track:
cmd += ' -t %.2d:%.2d:%09.6f' % (track['duration'] / 60 / 60, track['duration'] / 60 % 60, track['duration'] % 60)
cmd += ' ' + ' '.join('-metadata %s="%s"' % (k, v) for (k, v) in metadata.items())
cmd += replace_chars(' "%.2d - %s - %s.mp3"' % (track['track'], track['artist'], track['title']))
print(cmd)
@maye9999
Copy link

@OscarL Thank you very much❤

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment