From aca0714e7dbea2c3f5ef9a415a0e41d8692cb9d5 Mon Sep 17 00:00:00 2001 From: Eddy Pronk Date: Mon, 26 Nov 2007 08:21:33 +1100 Subject: [PATCH] refactored directory traversal, added support for .ape --- transcode/lineage.py | 109 ++++++++++++++++++++++---------- transcode/scan.py | 156 +++++++++++++++++++++++++++++++++------------- transcode/test_lineage.py | 68 ++++++++++++-------- transcode/transcode.py | 12 +++- 4 files changed, 240 insertions(+), 105 deletions(-) diff --git a/transcode/lineage.py b/transcode/lineage.py index 6d8f2f0..71d23c3 100644 --- a/transcode/lineage.py +++ b/transcode/lineage.py @@ -4,7 +4,7 @@ import os import album def log(level, s): - #print s + print s pass def all_same(l): @@ -23,15 +23,16 @@ class Lineage: def __init__(self): self.r = [] self.album = album.Album() - self.disk = self.album.disk(1) + self.last_track_number = 0 + self.selectDisc('1') self.checksums = {} - #self.add(('^d([0-9]+)t([0-9]+)', lambda r : self.insertAlbum(r.group(1)))) + #self.add(('^d([0-9]+)t([0-9]+)', lambda r : self.selectDisc(r.group(1)))) self.add(('([^:]+):([0-9a-f]{32})', lambda r : self.insertChecksum(r.group(1), r.group(2)))) self.add(('([0-9a-f]{32}) \*(.*)', lambda r : self.insertChecksum(r.group(2), r.group(1)))) self.add(('^([0-9]+)\.\s*(.*)', lambda r : self.insertTitle(r.group(1), r.group(2)))) self.add(('^([0-9]+) (.*)', lambda r : self.insertTitle(r.group(1), r.group(2)))) - self.add(('(DISC|Disc|cd|CD)\s*([0-9])', lambda r : self.insertAlbum(r.group(2)))) +# self.add(('(DISC|Disc|cd|CD)\s*([0-9])', lambda r : self.selectDisc(r.group(2)))) def extract(self): @@ -41,8 +42,18 @@ class Lineage: parse(line) album.do_print() + def parseDisc(self, s, comment): + res = re.search('(DISC|Disc|cd|CD)\s*([0-9])', s) + if res is not None: + disc_number = res.group(2) + print '[disc #%s matches, %s]' % (disc_number, comment) + self.selectDisc(disc_number) + def read(self, filename): - self.try_match(filename) # bit hacky + self.selectDisc('1') + print 'read %s' % filename + self.last_track_number = 0 + self.parseDisc(filename, 'matches filename') # bit hacky self.input_file = open(filename) self.readlines() @@ -54,9 +65,15 @@ class Lineage: self.try_match(line) self.process() - def insertAlbum(self, disk_number): - self.disk = self.album.disk(string.atoi(disk_number)) - log(2, '[disk #%s]' % disk_number) + def selectDisc(self, disc_number): + + self.disc = self.album.disc(string.atoi(disc_number)) + log(2, '[disc #%s]' % disc_number) + + def nextDisc(self): + disc_number = self.disc.number + 1 + log(2, '[disc #%s]' % disc_number) + self.disc = self.album.disc(disc_number) def insertTitle(self,number, title): track_number = string.atoi(number) @@ -64,52 +81,80 @@ class Lineage: log(1, '[IGNORE title #%s "%s"]' % (track_number, title)) return log(2, '[title #%s "%s"]' % (track_number, title)) - track = self.disk.track(track_number) - #track.title = " ".join([ word.capitalize() for word in title.split() ]) + + #print 'tr %d < last %d' % (track_number, self.last_track_number) + if (track_number < self.last_track_number): + self.nextDisc() + + self.last_track_number = track_number + + track = self.disc.track(track_number) res = re.search('(.*)[0-9]{2}:[0-9]{2}$', title) if res is not None: title = res.group(1) track.title = title.rstrip() track.title = track.title.replace(' / ', ', ') - def insertChecksum(self, filename, checksum): - log(2, '[checksum file=%s checksum=%s]' % (filename, checksum)) + def insertChecksum(self, path, checksum): + + # fix the directory seperator + path = path.replace('\\', '/') + + log(2, '[checksum file=%s checksum=%s]' % (path, checksum)) expr = '\.(flac|ape)$' - res = re.search(expr, filename) + res = re.search(expr, path) if res is not None: - dir, filename = os.path.split(filename) - self.try_match(dir) + dir, filename = os.path.split(path) + self.parseDisc(dir, 'in %s' % path) + # parse d1t3.ape res = re.search('^d([0-9]+)t([0-9]+)', filename) if res is not None: pass - self.insertAlbum(res.group(1)) + self.selectDisc(res.group(1)) + # parse 1-2.ape res = re.search('^([0-9]+)-([0-9]+)', filename) if res is not None: pass - self.insertAlbum(res.group(1)) + self.selectDisc(res.group(1)) - self.disk.checksums[filename] = checksum + # + res = re.search('^cd([0-9]+)', filename) + if res is not None: + pass + self.selectDisc(res.group(1)) + + self.disc.checksums[filename] = checksum else: print '[ignoring %s]' % filename - def write_cue_sheet(self, file): - for disk in self.album.disks.values(): - self.write_cue_sheet_(file, disk) + def write_cue_sheet(self): + for disc in self.album.discs.values(): + cue_filename = os.path.join(disc.content_root, 'disc%d.cue' % disc.number) - def write_cue_sheet_(self, file, disk): - print 'write_cue_sheet_ %i' % disk.number - #self.file = open(filename, 'w') + class FileFaker: + def write(self, string): + print string + + if not os.path.exists(cue_filename): + print 'writing cue file for disc #%i to %s' % (disc.number, cue_filename) + file = open(cue_filename, 'w') + self.write_cue_sheet_(file, disc) + else: + print 'writing cue file for disc #%i to %s (skipping, exists)' % (disc.number, cue_filename) + + def write_cue_sheet_(self, file, disc): #file = self.file file.write('PERFORMER ""\n') file.write('TITLE ""\n') file.write('YEAR ""\n') - file.write('DISC "%d"\n' % disk.number) + file.write('DISC "%d"\n' % disc.number) file.write('COMMENT "LAME 3.97 (--preset standard)"\n') file.write('\n') - for track in disk.tracks.values(): + for track in disc.tracks.values(): + track.title = " ".join([ word.capitalize() for word in track.title.split() ]) #file.write('TRACK %s AUDIO\n' % track.number) file.write('TRACK %s\n' % track.number) file.write(' TITLE "%s"\n' % track.title) @@ -118,14 +163,14 @@ class Lineage: #file.write(' CHECKSUM "%s"\n' % track.checksum) def process(self): - for disk in self.album.disks.values(): - log(2, '[DISK %d]' % disk.number) - res = find_diffs(disk.checksums.keys()) - for filename, checksum in disk.checksums.iteritems(): + for disc in self.album.discs.values(): + log(2, '[DISC %d]' % disc.number) + res = find_diffs(disc.checksums.keys()) + for filename, checksum in disc.checksums.iteritems(): track_number = string.atoi(re.search('([0-9]+)', filename[res:]).group(1)) #self.try_match(filename) - track = disk.track(track_number) + track = disc.track(track_number) track.filename = filename track.checksum = checksum @@ -144,7 +189,7 @@ class Lineage: expr,b = t res = re.search(expr, line) if res is not None: - log(3, '%s matches %s' % (line, expr)) + log(3, '[%s matches %s]' % (line, expr)) b(res) break diff --git a/transcode/scan.py b/transcode/scan.py index da3db07..943865a 100644 --- a/transcode/scan.py +++ b/transcode/scan.py @@ -1,10 +1,40 @@ +#! /usr/bin/env python + +# Copyright (C) 2007 Eddy Pronk +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + import os import re import glob import string import lineage +from optparse import OptionParser + +parser = OptionParser() + +(options, args) = parser.parse_args() + + +def chdir(dir): + #print 'chdir %s' % dir + os.chdir(dir) class Scanner: + def __init__(self, object): + self.object = object + def glob(self, parent, pattern): txt = glob.glob("*") newlist = [] @@ -16,46 +46,57 @@ class Scanner: return newlist def scan(self, dir): - self.disc = None - self.album_list = [] self.traverse(dir) - uniquedict = {} - for i in self.album_list: - uniquedict[i] = 0 - print def traverse(self, dir, parent = None): cwd = os.getcwd() - os.chdir(dir) - media_files = [] + chdir(dir) + self.object.on_enter_dir(dir, cwd) list = glob.glob("*") for l in list: if os.path.isdir(l): - res = re.search('(CD|Disc)\s*([0-9])', l) - if res is not None: - self.disc = string.atoi(res.group(2)) self.traverse(l, os.getcwd()) else: - expr = '\.(flac|ape)$' - res = re.search(expr, l) - if res is not None and os.path.isfile(l): - media_files.append(l) - - if len(media_files): - print - print 'media files for found in:' - print os.getcwd() + self.object.on_file(l) + + self.object.on_leaving_dir(os.getcwd(), cwd) + chdir(cwd) + +class FlayGuy: + def on_dir(self, dir): + print 'entering %s' % dir + def on_leaving_dir(self, file): + print 'leaving %s' % file + def on_file(self, file): + print 'file %s' % file + +class ScanGuy: + def __init__(self): + self.lineage = lineage.Lineage() + self.album_dir = '' + self.disc_number = 1 + self.parent_done = False # metadata in parent has not been read + + def on_enter_dir(self, dir, parent = None): + print 'entering %s' % dir + res = re.search('(CD|cd|Disc)\s*([0-9])', dir) + if res is not None: + self.disc_number = string.atoi(res.group(2)) + self.media_files = [] + + def on_leaving_dir(self, dir, parent = None): + if len(self.media_files): content_dir = os.getcwd() - album_dir = os.getcwd() - txt = self.glob(album_dir, '\.(txt|ffp|md5)$') + self.lineage.album.disc(self.disc_number).content_root = content_dir + print 'media files for disc %i in %s' % (self.disc_number, content_dir) + txt = self.glob(content_dir, '\.(txt|ffp|md5)$') if len(txt): print 'searching for meta data -- found!' else: print 'searching for meta data -- not found, trying parent dir' - if self.disc is not None: - print 'multi disc set, disk %s' % self.disc - os.chdir(parent) + if not self.parent_done: + chdir(parent) extra_txt = self.glob(parent, '\.(txt|ffp|md5)$') if len(extra_txt): @@ -64,35 +105,60 @@ class Scanner: txt.extend(extra_txt) else: print 'searching for meta data -- not found!' + self.parent_done = True - if len(txt): - print 'root %s' % album_dir - print txt + self.album_dir = album_dir + if len(txt): + print 'root %s' % album_dir + content_root = os.getcwd() - self.album_list.append(album_dir) + class FileFaker: + def write(self, string): + #print string + pass - print 'content in %s' % content_dir - ding = lineage.Lineage() + file = FileFaker() + for l in txt: + #log(2, 'read meta data from %s' % l) + self.lineage.read(l) + else: + print 'already have info from parent' - class FileFaker: - def write(self, string): - #print string - pass + print 'leaving %s' % dir - file = FileFaker() - for l in txt: - print 'read meta data from %s' % l - ding.read(l) + if dir == self.album_dir: + print 'RESET' + self.lineage.write_cue_sheet() + self.lineage = lineage.Lineage() + self.album_dir = '' + self.parent_done = False + self.media_files = [] - cue_filename = os.path.join(content_dir, 'tracklist.cue') - print 'writing cue file to %s' % cue_filename - ding.write_cue_sheet(file) + def on_file(self, file): + expr = '\.(flac|ape)$' + res = re.search(expr, file) + if res is not None and os.path.isfile(file): + self.media_files.append(file) - os.chdir(cwd) + def glob(self, parent, pattern): + txt = glob.glob("*") + newlist = [] + for l in txt: + res = re.search(pattern, l) + if res is not None and os.path.isfile(l): + newlist.append(os.path.join(parent, l)) + return newlist -s = Scanner() +f = ScanGuy() +s = Scanner(f) #s.scan('/media/data') -s.scan('/media/data/[05.24.92] Flanders Expo') +#s.scan('/media/data/done') +#s.scan('/media/data/done/Prince - Indigo2, London, 6 September 2007') +#s.scan('/home/epronk/4dafunk/4DaFunk/4DaFunk Open Sessions') +s.scan('/home/epronk/4dafunk') +#s.scan('/media/data/done/Rock Over Germany/') +#s.scan('/media/data/test') +#s.scan('/media/data/[05.24.92] Flanders Expo') #s.scan('/media/data/Prince and the Revolution - Stockholm 1986') #s.scan('/media/data/Parliament Funkadelic Unreleased SBD/') #s.scan('/media/data/done/test') #Prince - Indigo2, London, 6 September 2007/') diff --git a/transcode/test_lineage.py b/transcode/test_lineage.py index 5e2066c..fe4b868 100644 --- a/transcode/test_lineage.py +++ b/transcode/test_lineage.py @@ -52,11 +52,11 @@ class I(unittest.TestCase): class TestLineageLifetime(unittest.TestCase): def test_Empty(self): obj = lineage.Lineage() - self.assertEqual(len(obj.album.disks), 1) + self.assertEqual(len(obj.album.discs), 1) obj.try_match('DISC 2') - self.assertEqual(len(obj.album.disks), 2) + self.assertEqual(len(obj.album.discs), 2) obj = lineage.Lineage() - self.assertEqual(len(obj.album.disks), 1) + self.assertEqual(len(obj.album.discs), 1) class TestLineage(unittest.TestCase): @@ -64,18 +64,18 @@ class TestLineage(unittest.TestCase): def setUp(self): self.lineage = lineage.Lineage() - def testDisk(self): - disk = self.lineage.album.disk(1) + def testDisc(self): + disc = self.lineage.album.disc(1) def testTrack(self): line = '8. God Is A DJ' self.lineage.try_match(line) - self.assertEqual(self.lineage.album.disk(1).track(8).title, 'God Is A Dj') + self.assertEqual(self.lineage.album.disc(1).track(8).title, 'God Is A Dj') def testTrackWithoutSpace(self): line = '8.God Is A DJ' self.lineage.try_match(line) - self.assertEqual(self.lineage.album.disk(1).track(8).title, 'God Is A Dj') + self.assertEqual(self.lineage.album.disc(1).track(8).title, 'God Is A Dj') def testTrackWithoutSpace(self): self.lineage.try_match('CD2') @@ -86,29 +86,29 @@ class TestLineage(unittest.TestCase): #self.lineage.try_match('Track01.flac:1234567890abcdef0123456789012345') #self.lineage.try_match('Track02.flac:1234567890abcdef0123456789012345') #self.lineage.process() - self.assertEqual(self.lineage.album.disk(2).track(8).title, 'God Is A DJ') - self.assertEqual(self.lineage.album.disk(2).track(8).filename, 'Track08.flac') + self.assertEqual(self.lineage.album.disc(2).track(8).title, 'God Is A DJ') + self.assertEqual(self.lineage.album.disc(2).track(8).filename, 'Track08.flac') def testTrack(self): line = '08 God Is A DJ' self.assertEqual(self.lineage.try_match_test(line), ('08' , 'God Is A DJ')) self.lineage.try_match(line) - self.assertEqual(self.lineage.album.disk(1).track(8).title, 'God Is A DJ') + self.assertEqual(self.lineage.album.disc(1).track(8).title, 'God Is A DJ') def testRe(self): self.lineage.try_match_test('Track01.flac:1234567890abcdef0123456789012345') self.lineage.try_match_test('Track10.flac:1234567890abcdef0123456789012345') - self.assertEqual(self.lineage.try_match_test('DISC 2'), ('DISC' , '2')) - self.assertEqual(self.lineage.try_match_test('Disc 2'), ('Disc' , '2')) + #self.assertEqual(self.lineage.try_match_test('DISC 2'), ('DISC' , '2')) + #self.assertEqual(self.lineage.try_match_test('Disc 2'), ('Disc' , '2')) #self.assertEqual(self.lineage.try_match_test('d3t01.flac'), ('3' , '01')) def testChecksum1(self): self.lineage.try_match('Track01.flac:1234567890abcdef0123456789012345') self.lineage.try_match('Track02.flac:1234567890abcdef0123456789012345') self.lineage.process() - self.assertEqual(self.lineage.album.disk(1).track(1).filename, 'Track01.flac') - self.assertEqual(self.lineage.album.disk(1).track(1).checksum, '1234567890abcdef0123456789012345') + self.assertEqual(self.lineage.album.disc(1).track(1).filename, 'Track01.flac') + self.assertEqual(self.lineage.album.disc(1).track(1).checksum, '1234567890abcdef0123456789012345') def testChecksum2(self): input = ''' @@ -117,8 +117,8 @@ class TestLineage(unittest.TestCase): ''' self.lineage.input_file = FileFaker(input) self.lineage.readlines() - self.assertEqual(self.lineage.album.disk(1).track(8).filename, 'Faithless2005-08-19_t08.flac') - self.assertEqual(self.lineage.album.disk(1).track(8).checksum, '1234567890abcdef0123456789012345') + self.assertEqual(self.lineage.album.disc(1).track(8).filename, 'Faithless2005-08-19_t08.flac') + self.assertEqual(self.lineage.album.disc(1).track(8).checksum, '1234567890abcdef0123456789012345') def testChecksum3(self): input = ''' @@ -128,13 +128,13 @@ class TestLineage(unittest.TestCase): ''' self.lineage.input_file = FileFaker(input) self.lineage.readlines() - self.assertEqual(self.lineage.album.disk(1).track(10).filename, '10. Take The Long Way Home.ape') + self.assertEqual(self.lineage.album.disc(1).track(10).filename, '10. Take The Long Way Home.ape') - def testFilenameWithDiskNumber(self): + def testFilenameWithDiscNumber(self): self.lineage.try_match('d1t01.flac') - #self.assertEqual(self.lineage.disk.number, 1) + #self.assertEqual(self.lineage.disc.number, 1) self.lineage.try_match('d2t01.flac') - #self.assertEqual(self.lineage.disk.number, 2) + #self.assertEqual(self.lineage.disc.number, 2) def testDetectNumber(self): @@ -142,9 +142,18 @@ class TestLineage(unittest.TestCase): self.lineage.try_match('1234567890abcdef0123456789012345 *Faithless2005-08-19_t02.flac') self.lineage.try_match('1234567890abcdef0123456789012345 *Faithless2005-08-19_t07.flac') self.lineage.process() - self.assertEqual(self.lineage.album.disk(1).track(7).filename, 'Faithless2005-08-19_t07.flac') + self.assertEqual(self.lineage.album.disc(1).track(7).filename, 'Faithless2005-08-19_t07.flac') - def testMultiDisk(self): + def testDetectNumberWithBackslash(self): + self.lineage.try_match('1234567890abcdef0123456789012345 *cd1\Faithless2005-08-19_t01.flac') + self.lineage.try_match('1234567890abcdef0123456789012345 *cd1\Faithless2005-08-19_t02.flac') + self.lineage.try_match('1234567890abcdef0123456789012345 *cd2\Faithless2005-08-19_t03.flac') + self.lineage.try_match('1234567890abcdef0123456789012345 *cd2\Faithless2005-08-19_t04.flac') + self.lineage.process() + self.assertEqual(self.lineage.album.disc(1).track(1).filename, 'Faithless2005-08-19_t01.flac') + self.assertEqual(self.lineage.album.disc(2).track(3).filename, 'Faithless2005-08-19_t03.flac') + + def testMultiDisc(self): class FileFaker: def write(self, string): @@ -154,10 +163,19 @@ class TestLineage(unittest.TestCase): self.lineage.try_match('DISC 1') self.lineage.try_match('DISC 2') self.lineage.try_match('8. God Is A DJ') - self.assertEqual(self.lineage.album.disk(2).track(8).title, 'God Is A DJ') + self.assertEqual(self.lineage.album.disc(2).track(8).title, 'God Is A DJ') file = FileFaker() - self.lineage.write_cue_sheet(file) + self.lineage.write_cue_sheet() + def testMultiDisc(self): + self.lineage.try_match("01. Reverence") + self.lineage.try_match("02. She's My Baby") + self.lineage.try_match("01. Reverence") + self.lineage.try_match("02. She's My Baby") + self.lineage.process() + self.assertEqual(self.lineage.album.disc(1).track(1).title, "Reverence") + self.assertEqual(self.lineage.album.disc(2).track(1).title, "Reverence") + def testExample(self): input = ''' 01. Faithless - Reverence @@ -173,7 +191,7 @@ class TestLineage(unittest.TestCase): self.lineage.input_file = FileFaker(input) file = FileFaker() self.lineage.readlines() - self.lineage.write_cue_sheet(file) + self.lineage.write_cue_sheet() if __name__ == '__main__': diff --git a/transcode/transcode.py b/transcode/transcode.py index b35a34d..ae0441f 100644 --- a/transcode/transcode.py +++ b/transcode/transcode.py @@ -19,7 +19,11 @@ import string import cuesheet import os -file = open('montreux.cue') +cue_sheet = '/home/epronk/4dafunk/4DaFunk/4DaFunk Open Sessions/cd1/disc1.cue' + +dir, filename = os.path.split(cue_sheet) +os.chdir(dir) +file = open(filename) input = file.read() tokens = cuesheet.parse('sheet', input) @@ -82,6 +86,8 @@ for track in album.tracks.values(): opt.option('--tn', track.number) # track filename = os.path.join(dir, '%02d. %s.mp3' % (track.number, track.title)) - cmd = 'flac --decode --silent --stdout "%s" | lame - "%s" --preset standard ' % (track.file, filename) + ' '.join(opt.str) + lame = 'lame - "%s" --quiet --preset standard ' % filename + ' '.join(opt.str) + #cmd = 'flac --decode --silent --stdout "%s" | %s' % (track.file, lame) + cmd = 'mac "%s" /dev/stdout -d 2>&1 >/dev/null| %s>/dev/null' % (track.file, lame) print cmd - os.system(cmd) + #os.system(cmd) -- 2.11.4.GIT