From 13ec4b540e0d46c97fd7b089e0b7413da81e0a9f Mon Sep 17 00:00:00 2001 From: Marius Date: Sun, 19 May 2013 20:40:34 +0300 Subject: beta 2013.05.19 19:27 --- scripts/context/lua/mtx-flac.lua | 476 +++++++++++++++++++-------------------- 1 file changed, 238 insertions(+), 238 deletions(-) (limited to 'scripts/context/lua/mtx-flac.lua') diff --git a/scripts/context/lua/mtx-flac.lua b/scripts/context/lua/mtx-flac.lua index 2155b24be..2e988b412 100644 --- a/scripts/context/lua/mtx-flac.lua +++ b/scripts/context/lua/mtx-flac.lua @@ -1,238 +1,238 @@ -if not modules then modules = { } end modules ['mtx-flac'] = { - version = 1.001, - comment = "companion to mtxrun.lua", - author = "Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright = "PRAGMA ADE / ConTeXt Development Team", - license = "see context related readme files" -} - -local sub, match, byte, lower = string.sub, string.match, string.byte, string.lower -local readstring, readnumber = io.readstring, io.readnumber -local concat, sortedpairs = table.concat, table.sortedpairs -local tonumber = tonumber -local tobitstring = number.tobitstring -local lpegmatch = lpeg.match -local p_escaped = lpeg.patterns.xml.escaped - --- rather silly: pack info in bits while a flac file is large anyway - -flac = flac or { } - -flac.report = string.format - -local splitter = lpeg.splitat("=") -local readers = { } - -readers[0] = function(f,size,target) -- not yet ok .. todo: use bit32 lib - local info = { } - target.info = info - info.minimum_block_size = readnumber(f,-2) - info.maximum_block_size = readnumber(f,-2) - info.minimum_frame_size = readnumber(f,-3) - info.maximum_frame_size = readnumber(f,-3) - local buffer = { } - for i=1,8 do - buffer[i] = tobitstring(readnumber(f,1)) - end - local bytes = concat(buffer) - info.sample_rate_in_hz = tonumber(sub(bytes, 1,20),2) -- 20 - info.number_of_channels = tonumber(sub(bytes,21,23),2) -- 3 - info.bits_per_sample = tonumber(sub(bytes,24,28),2) -- 5 - info.samples_in_stream = tonumber(sub(bytes,29,64),2) -- 36 - info.md5_signature = readstring(f,16) -- 128 -end - -readers[4] = function(f,size,target,banner) - local tags = { } - target.tags = tags - target.vendor = readstring(f,readnumber(f,-4)) - for i=1,readnumber(f,-4) do - local key, value = lpeg.match(splitter,readstring(f,readnumber(f,-4))) - tags[lower(key)] = value - end -end - -readers.default = function(f,size,target) - f:seek("cur",size) -end - -function flac.getmetadata(filename) - local f = io.open(filename, "rb") - if f then - local banner = readstring(f,4) - if banner == "fLaC" then - local data = { - banner = banner, - filename = filename, - filesize = lfs.attributes(filename,"size"), - } - while true do - local flag = readnumber(f,1) - local size = readnumber(f,3) - local last = flag > 127 - if last then - flag = flag - 128 - end - local reader = readers[flag] or readers.default - reader(f,size,data,banner) - if last then - f:close() - return data - end - end - else - flac.report("no flac file: %s (%s)",filename,banner) - end - f:close() - else - flac.report("no file: %s",filename) - end -end - -function flac.savecollection(pattern,filename) - pattern = (pattern ~= "" and pattern) or "**/*.flac" - filename = (filename ~= "" and filename) or "music-collection.xml" - flac.report("identifying files using pattern %q" ,pattern) - local files = dir.glob(pattern) - flac.report("%s files found, analyzing files",#files) - local music = { } - for i=1,#files do - local data = flac.getmetadata(files[i]) - if data then - local tags = data.tags - local info = data.info - local artist = tags.artist - local album = tags.album - local albums = music[artist] - if not albums then - albums = { } - music[artist] = albums - end - local albumx = albums[album] - if not albumx then - albumx = { - year = tags.date, - tracks = { }, - } - albums[album] = albumx - end - albumx.tracks[tonumber(tags.tracknumber) or 0] = { - title = tags.title, - length = math.round((info.samples_in_stream/info.sample_rate_in_hz)), - } - end - end - -- inspect(music) - local nofartists, nofalbums, noftracks, noferrors = 0, 0, 0, 0 - local f = io.open(filename,"wb") - if f then - flac.report("saving data in file %q",filename) - f:write("\n\n") - f:write("\n") - for artist, albums in sortedpairs(music) do - nofartists = nofartists + 1 - f:write("\t\n") - f:write("\t\t",lpegmatch(p_escaped,artist),"\n") - f:write("\t\t\n") - for album, data in sortedpairs(albums) do - nofalbums = nofalbums + 1 - f:write("\t\t\t\n") - f:write("\t\t\t\t",lpegmatch(p_escaped,album),"\n") - f:write("\t\t\t\t\n") - local tracks = data.tracks - for i=1,#tracks do - local track = tracks[i] - if track then - noftracks = noftracks + 1 - f:write("\t\t\t\t\t",lpegmatch(p_escaped,track.title),"\n") - else - noferrors = noferrors + 1 - flac.report("error in album: %q of %q, no track %s",album,artist,i) - f:write("\t\t\t\t\t\n") - end - end - f:write("\t\t\t\t\n") - f:write("\t\t\t\n") - end - f:write("\t\t\n") - f:write("\t\n") - end - f:write("\n") - f:close() - flac.report("%s tracks of %s albums of %s artists saved in %q (%s errors)",noftracks,nofalbums,nofartists,filename,noferrors) - else - flac.report("unable to save data in file %q",filename) - end -end - --- - -local helpinfo = [[ - - - - mtx-flac - ConTeXt Flac Helpers - 0.10 - - - - - collect albums in xml file - - - - - - Example - - mtxrun --script flac --collect somename.flac - mtxrun --script flac --collect --pattern="m:/music/**") - - - - -]] - -local application = logs.application { - name = "mtx-flac", - banner = "ConTeXt Flac Helpers 0.10", - helpinfo = helpinfo, -} - -flac.report = application.report - --- script code - -scripts = scripts or { } -scripts.flac = scripts.flac or { } - -function scripts.flac.collect() - local files = environment.files - local pattern = environment.arguments.pattern - if #files > 0 then - for i=1,#files do - local filename = files[1] - if file.suffix(filename) == "flac" then - flac.savecollection(filename,file.replacesuffix(filename,"xml")) - elseif lfs.isdir(filename) then - local pattern = filename .. "/**.flac" - flac.savecollection(pattern,file.addsuffix(file.basename(filename),"xml")) - else - flac.savecollection(file.replacesuffix(filename,"flac"),file.replacesuffix(filename,"xml")) - end - end - elseif pattern then - flac.savecollection(file.addsuffix(pattern,"flac"),"music-collection.xml") - else - flac.report("no file(s) or pattern given" ) - end -end - -if environment.argument("collect") then - scripts.flac.collect() -elseif environment.argument("exporthelp") then - application.export(environment.argument("exporthelp"),environment.files[1]) -else - application.help() -end +if not modules then modules = { } end modules ['mtx-flac'] = { + version = 1.001, + comment = "companion to mtxrun.lua", + author = "Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright = "PRAGMA ADE / ConTeXt Development Team", + license = "see context related readme files" +} + +local sub, match, byte, lower = string.sub, string.match, string.byte, string.lower +local readstring, readnumber = io.readstring, io.readnumber +local concat, sortedpairs = table.concat, table.sortedpairs +local tonumber = tonumber +local tobitstring = number.tobitstring +local lpegmatch = lpeg.match +local p_escaped = lpeg.patterns.xml.escaped + +-- rather silly: pack info in bits while a flac file is large anyway + +flac = flac or { } + +flac.report = string.format + +local splitter = lpeg.splitat("=") +local readers = { } + +readers[0] = function(f,size,target) -- not yet ok .. todo: use bit32 lib + local info = { } + target.info = info + info.minimum_block_size = readnumber(f,-2) + info.maximum_block_size = readnumber(f,-2) + info.minimum_frame_size = readnumber(f,-3) + info.maximum_frame_size = readnumber(f,-3) + local buffer = { } + for i=1,8 do + buffer[i] = tobitstring(readnumber(f,1)) + end + local bytes = concat(buffer) + info.sample_rate_in_hz = tonumber(sub(bytes, 1,20),2) -- 20 + info.number_of_channels = tonumber(sub(bytes,21,23),2) -- 3 + info.bits_per_sample = tonumber(sub(bytes,24,28),2) -- 5 + info.samples_in_stream = tonumber(sub(bytes,29,64),2) -- 36 + info.md5_signature = readstring(f,16) -- 128 +end + +readers[4] = function(f,size,target,banner) + local tags = { } + target.tags = tags + target.vendor = readstring(f,readnumber(f,-4)) + for i=1,readnumber(f,-4) do + local key, value = lpeg.match(splitter,readstring(f,readnumber(f,-4))) + tags[lower(key)] = value + end +end + +readers.default = function(f,size,target) + f:seek("cur",size) +end + +function flac.getmetadata(filename) + local f = io.open(filename, "rb") + if f then + local banner = readstring(f,4) + if banner == "fLaC" then + local data = { + banner = banner, + filename = filename, + filesize = lfs.attributes(filename,"size"), + } + while true do + local flag = readnumber(f,1) + local size = readnumber(f,3) + local last = flag > 127 + if last then + flag = flag - 128 + end + local reader = readers[flag] or readers.default + reader(f,size,data,banner) + if last then + f:close() + return data + end + end + else + flac.report("no flac file: %s (%s)",filename,banner) + end + f:close() + else + flac.report("no file: %s",filename) + end +end + +function flac.savecollection(pattern,filename) + pattern = (pattern ~= "" and pattern) or "**/*.flac" + filename = (filename ~= "" and filename) or "music-collection.xml" + flac.report("identifying files using pattern %q" ,pattern) + local files = dir.glob(pattern) + flac.report("%s files found, analyzing files",#files) + local music = { } + for i=1,#files do + local data = flac.getmetadata(files[i]) + if data then + local tags = data.tags + local info = data.info + local artist = tags.artist + local album = tags.album + local albums = music[artist] + if not albums then + albums = { } + music[artist] = albums + end + local albumx = albums[album] + if not albumx then + albumx = { + year = tags.date, + tracks = { }, + } + albums[album] = albumx + end + albumx.tracks[tonumber(tags.tracknumber) or 0] = { + title = tags.title, + length = math.round((info.samples_in_stream/info.sample_rate_in_hz)), + } + end + end + -- inspect(music) + local nofartists, nofalbums, noftracks, noferrors = 0, 0, 0, 0 + local f = io.open(filename,"wb") + if f then + flac.report("saving data in file %q",filename) + f:write("\n\n") + f:write("\n") + for artist, albums in sortedpairs(music) do + nofartists = nofartists + 1 + f:write("\t\n") + f:write("\t\t",lpegmatch(p_escaped,artist),"\n") + f:write("\t\t\n") + for album, data in sortedpairs(albums) do + nofalbums = nofalbums + 1 + f:write("\t\t\t\n") + f:write("\t\t\t\t",lpegmatch(p_escaped,album),"\n") + f:write("\t\t\t\t\n") + local tracks = data.tracks + for i=1,#tracks do + local track = tracks[i] + if track then + noftracks = noftracks + 1 + f:write("\t\t\t\t\t",lpegmatch(p_escaped,track.title),"\n") + else + noferrors = noferrors + 1 + flac.report("error in album: %q of %q, no track %s",album,artist,i) + f:write("\t\t\t\t\t\n") + end + end + f:write("\t\t\t\t\n") + f:write("\t\t\t\n") + end + f:write("\t\t\n") + f:write("\t\n") + end + f:write("\n") + f:close() + flac.report("%s tracks of %s albums of %s artists saved in %q (%s errors)",noftracks,nofalbums,nofartists,filename,noferrors) + else + flac.report("unable to save data in file %q",filename) + end +end + +-- + +local helpinfo = [[ + + + + mtx-flac + ConTeXt Flac Helpers + 0.10 + + + + + collect albums in xml file + + + + + + Example + + mtxrun --script flac --collect somename.flac + mtxrun --script flac --collect --pattern="m:/music/**") + + + + +]] + +local application = logs.application { + name = "mtx-flac", + banner = "ConTeXt Flac Helpers 0.10", + helpinfo = helpinfo, +} + +flac.report = application.report + +-- script code + +scripts = scripts or { } +scripts.flac = scripts.flac or { } + +function scripts.flac.collect() + local files = environment.files + local pattern = environment.arguments.pattern + if #files > 0 then + for i=1,#files do + local filename = files[1] + if file.suffix(filename) == "flac" then + flac.savecollection(filename,file.replacesuffix(filename,"xml")) + elseif lfs.isdir(filename) then + local pattern = filename .. "/**.flac" + flac.savecollection(pattern,file.addsuffix(file.basename(filename),"xml")) + else + flac.savecollection(file.replacesuffix(filename,"flac"),file.replacesuffix(filename,"xml")) + end + end + elseif pattern then + flac.savecollection(file.addsuffix(pattern,"flac"),"music-collection.xml") + else + flac.report("no file(s) or pattern given" ) + end +end + +if environment.argument("collect") then + scripts.flac.collect() +elseif environment.argument("exporthelp") then + application.export(environment.argument("exporthelp"),environment.files[1]) +else + application.help() +end -- cgit v1.2.3