def consoleRipper(writeDirectory): # Rip audio to to WAV or FLAC (depending on dBpoweramps settings in default profile) # Uses the bespoke dBpoweramp console ripper which was developed at request of KB # dBpoweramp\kb-nl-consolerip.exe" --drive="D" --log=E:\cdBatchesTest\testconsolerip\log.txt --path=E:\cdBatchesTest\testconsolerip\ # # NOTE: logFile doesn't offer anything that's not in the secure extraction log # So it is simply discarded after ripping logFile = os.path.join(config.tempDir,shared.randomString(12) + ".log") secureExtractionLogFile = os.path.join(writeDirectory, "dbpoweramp.log") args = [config.dBpowerampConsoleRipExe] args.append("".join(["--drive=", config.cdDriveLetter])) args.append("".join(["--log=", logFile])) args.append("".join(["--path=", writeDirectory])) # Command line as string (used for logging purposes only) cmdStr = " ".join(args) status, out, err = shared.launchSubProcess(args) with io.open(logFile, "r", encoding="utf-8-sig") as fLog: log = fLog.read() fLog.close() # Remove log file os.remove(logFile) # Read Secure Extraction log and convert to UTF-8 with io.open(secureExtractionLogFile, "r", encoding="utf-16") as fSecureExtractionLogFile: text = fSecureExtractionLogFile.read() fSecureExtractionLogFile.close() with io.open(secureExtractionLogFile, "w", encoding="utf-8") as fSecureExtractionLogFile: fSecureExtractionLogFile.write(text) fSecureExtractionLogFile.close() # All results to dictionary dictOut = {} dictOut["cmdStr"] = cmdStr dictOut["status"] = status dictOut["stdout"] = out dictOut["stderr"] = err dictOut["log"] = log return(dictOut)
def getDrives(): # Returns list of all optical drives # cd-info command line: # cd-info -l args = [config.cdInfoExe] args.append("-l") # Command line as string (used for logging purposes only) cmdStr = " ".join(args) status, out, err = shared.launchSubProcess(args) # Output lines to list outAsList = out.splitlines() # Set up list for storing identified drives drives = [] # Locate track list and analysis report in cd-info output startIndexDevicesList = shared.index_startswith_substring( outAsList, "list of devices found:") # Parse devices list and store Drive entries to list for i in range(startIndexDevicesList + 1, len(outAsList), 1): thisLine = outAsList[i] if thisLine.startswith("Drive") == True: thisDrive = thisLine.split("\\\\.\\") driveLetter = thisDrive[1].strip(":\n") drives.append(driveLetter) # Main results to dictionary dictOut = {} dictOut["cmdStr"] = cmdStr dictOut["drives"] = drives dictOut["status"] = status dictOut["stdout"] = out dictOut["stderr"] = err return (dictOut)
def load(): logFile = os.path.join(config.tempDir, shared.randomString(12) + ".log") errorFile = os.path.join(config.tempDir, shared.randomString(12) + ".err") args = [config.loadExe] args.append("--drive=" + config.cdDriveLetter) args.append("--rejectifnodisc") args.append("--logfile=" + logFile) args.append("--passerrorsback=" + errorFile) # Command line as string (used for logging purposes only) cmdStr = " ".join(args) status, out, err = shared.launchSubProcess(args) fLog = open(logFile, 'r') fErr = open(errorFile, 'r') log = fLog.read() errors = fErr.read() # Convert log and errors from little-Endian UTF-16 to UTF-8 logUTF8 = log.encode('utf-8').decode('utf-16le') errorsUTF8 = errors.encode('utf-8').decode('utf-16le') fLog.close() fErr.close() os.remove(logFile) os.remove(errorFile) # All results to dictionary dictOut = {} dictOut["cmdStr"] = cmdStr dictOut["status"] = status dictOut["stdout"] = out dictOut["stderr"] = err dictOut["log"] = logUTF8 dictOut["errors"] = errorsUTF8 return (dictOut)
def getCarrierInfo(writeDirectory): # Determine carrier type and number of sessions on carrier # cd-info command line: # cd-info -C d: --no-header --no-device-info --no-cddb --dvd ## TEST #config.cdInfoExe = "C:/Users/jkn010/iromlab/tools/libcdio/win64/cd-info.exe" #config.cdDriveLetter = "D" ## TEST cdInfoLogFile = os.path.join(writeDirectory, "cd-info.log") args = [config.cdInfoExe] args.append("-C") args.append("".join([config.cdDriveLetter, ":"])) args.append("--no-header") args.append("--no-device-info") args.append("--no-disc-mode") args.append("--no-cddb") args.append("--dvd") # Command line as string (used for logging purposes only) cmdStr = " ".join(args) status, out, err = shared.launchSubProcess(args) # Output lines to list outAsList = out.splitlines() # Set up dictionary and list for storing track list and analysis report trackList = [] analysisReport = [] # Locate track list and analysis report in cd-info output startIndexTrackList = shared.index_startswith_substring( outAsList, "CD-ROM Track List") startIndexAnalysisReport = shared.index_startswith_substring( outAsList, "CD Analysis Report") # Parse track list and store interesting bits in dictionary for i in range(startIndexTrackList + 2, startIndexAnalysisReport - 1, 1): thisTrack = outAsList[i] if thisTrack.startswith("++") == False: thisTrack = thisTrack.split(": ") trackNumber = int(thisTrack[0].strip()) trackDetails = thisTrack[1].split() trackMSFStart = trackDetails[0] # Minute:Second:Frame trackLSNStart = trackDetails[1] # Logical Sector Number trackType = trackDetails[2] trackProperties = {} trackProperties['trackNumber'] = trackNumber trackProperties['trackMSFStart'] = trackMSFStart trackProperties['trackLSNStart'] = trackLSNStart trackProperties['trackType'] = trackType trackList.append(trackProperties) # Flags for presence of audio / data tracks containsAudio = False containsData = False dataTrackLSNStart = '0' for track in trackList: if track['trackType'] == 'audio': containsAudio = True if track['trackType'] == 'data': containsData = True dataTrackLSNStart = track['trackLSNStart'] # Parse analysis report for i in range(startIndexAnalysisReport + 1, len(outAsList), 1): thisLine = outAsList[i] if thisLine.startswith("++") == False: analysisReport.append(thisLine) # Flags for CD/Extra / multisession / mixed-mode # Note that single-session mixed mode CDs are erroneously reported as # multisession by libcdio. See: http://savannah.gnu.org/bugs/?49090#comment1 cdExtra = shared.index_startswith_substring(analysisReport, "CD-Plus/Extra") != -1 multiSession = shared.index_startswith_substring(analysisReport, "session #") != -1 mixedMode = shared.index_startswith_substring(analysisReport, "mixed mode CD") != -1 # Write cd-info output to log file with io.open(cdInfoLogFile, "w", encoding="utf-8") as fCdInfoLogFile: for line in outAsList: fCdInfoLogFile.write(line + "\n") fCdInfoLogFile.close() # Main results to dictionary dictOut = {} dictOut["cmdStr"] = cmdStr dictOut["cdExtra"] = cdExtra dictOut["multiSession"] = multiSession dictOut["mixedMode"] = mixedMode dictOut["containsAudio"] = containsAudio dictOut["containsData"] = containsData dictOut["dataTrackLSNStart"] = dataTrackLSNStart dictOut["status"] = status dictOut["stdout"] = out dictOut["stderr"] = err return (dictOut)
def verifyAudioFile(audioFile, format): # Verify integrity of an audio file (check for missing / truncated bytes) if format == "wav": # Check with shntool args = [config.shntoolExe] #args = ["C:/Users/jkn010/iromlab/tools/shntool/shntool.exe"] args.append("info") args.append(audioFile) # Command line as string (used for logging purposes only) cmdStr = " ".join(args) status, out, err = shared.launchSubProcess(args) # Output lines to list outAsList = out.splitlines() noLines = len(outAsList) # Set up dictionary for storing values on reported problems problems = {} problemsAsList = [] # Locate problems report startIndexProblems = shared.index_startswith_substring( outAsList, "Possible problems:") # Parse problems list and store as dictionary for i in range(startIndexProblems + 1, noLines, 1): thisLine = outAsList[i] lineAsList = thisLine.split(":") problemName = lineAsList[0].strip() problemValue = lineAsList[1].strip() problems[problemName] = problemValue problemsAsList.append(thisLine.strip()) try: if problems["Inconsistent header"] != "no": isOK = False elif problems["File probably truncated"] != "no": isOK = False elif problems["Junk appended to file"] != "no": isOK = False else: isOK = True except KeyError: isOK = False # Add file reference as first element of errors list (used for logging only) problemsAsList.insert(0, "File: " + audioFile) return (isOK, status, problemsAsList) elif format == "flac": # Check with flac args = [config.flacExe] #args = ["C:/Users/jkn010/iromlab/tools/flac/win64/flac.exe"] args.append("-s") args.append("-t") args.append(audioFile) # Command line as string (used for logging purposes only) cmdStr = " ".join(args) status, out, err = shared.launchSubProcess(args) # Output lines to list (flac output is sent to stderr!) errAsList = err.splitlines() if (len(errAsList)) == 0: # No errors encountered isOK = True else: isOK = False # Add file reference as first element of errors list (used for logging only) errAsList.insert(0, "File: " + audioFile) return (isOK, status, errAsList)
def extractData(writeDirectory, session, dataTrackLSNStart): # IsoBuster /d:i /ei:"E:\nimbieTest\myDiskIB.iso" /et:u /ep:oea /ep:npc /c /m /nosplash /s:1 /l:"E:\nimbieTest\ib.log" # Temporary name for ISO file; base name isoFileTemp = os.path.join(writeDirectory, "disc.iso") #isoFile = os.path.join(writeDirectory, isoName) logFile = os.path.join(writeDirectory, "isobuster.log") args = [config.isoBusterExe] args.append("".join(["/d:", config.cdDriveLetter, ":"])) args.append("".join(["/ei:", isoFileTemp])) args.append("/et:u") args.append("/ep:oea") args.append("/ep:npc") args.append("/c") args.append("/m") args.append("/nosplash") args.append("".join(["/s:", str(session)])) args.append("".join(["/l:", logFile])) # Command line as string (used for logging purposes only) cmdStr = " ".join(args) status, out, err = shared.launchSubProcess(args) # Open and read log file with io.open(logFile, "r", encoding="cp1252") as fLog: log = fLog.read() fLog.close() # Rewrite as UTF-8 with io.open(logFile, "w", encoding="utf-8") as fLog: fLog.write(log) fLog.close() # Run isolyzer ISO try: isolyzerResult = isolyzer.processImage(isoFileTemp, dataTrackLSNStart) # Isolyzer status isolyzerSuccess = isolyzerResult.find('statusInfo/success').text # Is ISO image smaller than expected (if True, this indicates the image may be truncated) imageTruncated = isolyzerResult.find('tests/smallerThanExpected').text # Volume identifier from ISO's Primary Volume Descriptor volumeIdentifier = isolyzerResult.find( 'properties/primaryVolumeDescriptor/volumeIdentifier').text.strip( ) if volumeIdentifier != '': # Rename ISO image using volumeIdentifier as a base name # Any spaces in volumeIdentifier are replaced with dashes isoFile = os.path.join(writeDirectory, volumeIdentifier.replace(' ', '-') + '.iso') os.rename(isoFileTemp, isoFile) except IOError or AttributeError: volumeIdentifier = '' isolyzerSuccess = False imageTruncated = True # TODO: for added security we could also verify the ISO's MD5 against MD5 of physical disc. But this # is slow + implementation under Windows will be ugly (with possible dependency on Cygwin because # not clear if Windows supports Unix-syle device paths) # All results to dictionary dictOut = {} dictOut["cmdStr"] = cmdStr dictOut["status"] = status dictOut["stdout"] = out dictOut["stderr"] = err dictOut["log"] = log dictOut["volumeIdentifier"] = volumeIdentifier dictOut["isolyzerSuccess"] = isolyzerSuccess dictOut["imageTruncated"] = imageTruncated return (dictOut)