mirror of
https://github.com/OPSnet/Logchecker.git
synced 2026-01-16 18:04:27 -05:00
create decode and translate commands
This commit is contained in:
@@ -27,12 +27,12 @@ before_install:
|
||||
install:
|
||||
- composer install --ansi --prefer-dist --no-interaction --optimize-autoloader --no-suggest --no-progress
|
||||
- pip3 install --user chardet xld_logchecker eac_logchecker
|
||||
|
||||
|
||||
script:
|
||||
- bin/logchecker --version
|
||||
- bin/logchecker --help
|
||||
- bin/logchecker tests/logs/wgdbcm.log
|
||||
- bin/logchecker tests/logs/xld_perfect.log
|
||||
- bin/logchecker analyze tests/logs/wgdbcm.log
|
||||
- bin/logchecker analyze tests/logs/xld_perfect.log
|
||||
|
||||
before_deploy:
|
||||
- php -d phar.readonly=0 bin/compile
|
||||
@@ -46,4 +46,4 @@ deploy:
|
||||
on:
|
||||
tags: true
|
||||
repo: OPSnet/Logchecker
|
||||
php: '7.2'
|
||||
php: '7.2'
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "orpheusnet/logchecker",
|
||||
"description": "Logchecker for validating logs generated from supported ripping programs (like EAC and XLD)",
|
||||
"version": "0.8.6",
|
||||
"version": "0.9.0",
|
||||
"license": "Unlicense",
|
||||
"type": "library",
|
||||
"authors": [
|
||||
|
||||
@@ -3,12 +3,11 @@
|
||||
namespace OrpheusNET\Logchecker;
|
||||
|
||||
use OrpheusNET\Logchecker\Exception\FileNotFoundException;
|
||||
use Symfony\Component\Process\Exception\ProcessFailedException;
|
||||
use Symfony\Component\Process\Process;
|
||||
|
||||
class Chardet
|
||||
{
|
||||
private $executable = null;
|
||||
private static $executable = null;
|
||||
private $executables = [
|
||||
'chardet',
|
||||
'chardetect'
|
||||
@@ -16,15 +15,17 @@ class Chardet
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
foreach ($this->executables as $executable) {
|
||||
if (Util::commandExists($executable)) {
|
||||
$this->executable = $executable;
|
||||
break;
|
||||
if (static::$executable === null) {
|
||||
foreach ($this->executables as $executable) {
|
||||
if (Util::commandExists($executable)) {
|
||||
static::$executable = $executable;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($this->executable === null) {
|
||||
throw new \RuntimeException('chardet not installed');
|
||||
if (static::$executable === null) {
|
||||
throw new \RuntimeException('chardet not installed');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,7 +36,7 @@ class Chardet
|
||||
throw new FileNotFoundException($filename);
|
||||
}
|
||||
|
||||
$process = new Process([$this->executable, $filename]);
|
||||
$process = new Process([static::$executable, $filename]);
|
||||
$process->run();
|
||||
|
||||
// Following regex:
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<?php
|
||||
|
||||
namespace OrpheusNET\Logchecker\Checks;
|
||||
namespace OrpheusNET\Logchecker\Check;
|
||||
|
||||
use OrpheusNET\Logchecker\Util;
|
||||
use Symfony\Component\Process\Process;
|
||||
@@ -1,6 +1,6 @@
|
||||
<?php
|
||||
|
||||
namespace OrpheusNET\Logchecker\Checks;
|
||||
namespace OrpheusNET\Logchecker\Check;
|
||||
|
||||
class ChecksumStates
|
||||
{
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace OrpheusNET\Logchecker\Checks;
|
||||
namespace OrpheusNET\Logchecker\Check;
|
||||
|
||||
use OrpheusNET\Logchecker\Exception\UnknownRipperException;
|
||||
|
||||
@@ -21,10 +21,13 @@ class Ripper
|
||||
return Ripper::XLD;
|
||||
} elseif (strpos($log, "Exact Audio Copy") !== false) {
|
||||
return Ripper::EAC;
|
||||
} else if (strpos($log, "EAC") === 0) {
|
||||
return Ripper::EAC;
|
||||
} else {
|
||||
throw new UnknownRipperException("Could not determine ripper");
|
||||
$firstLine = strstr($log, "\n", true);
|
||||
if ($firstLine !== false && strpos($firstLine, "EAC") !== false) {
|
||||
return Ripper::EAC;
|
||||
} else {
|
||||
throw new UnknownRipperException("Could not determine ripper");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
51
src/Command/DecodeCommand.php
Normal file
51
src/Command/DecodeCommand.php
Normal file
@@ -0,0 +1,51 @@
|
||||
<?php
|
||||
|
||||
namespace OrpheusNET\Logchecker\Command;
|
||||
|
||||
use OrpheusNET\Logchecker\Util;
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Input\InputArgument;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
|
||||
class DecodeCommand extends Command
|
||||
{
|
||||
protected function configure()
|
||||
{
|
||||
$this
|
||||
->setName('decode')
|
||||
->setDescription('Decodes log from whatever encoding into UTF-8')
|
||||
->setHelp(<<<HELP
|
||||
This command decodes a log from whatever encoding into UTF-8.
|
||||
|
||||
XLD and Whipper generates logs that are in UTF-8, while EAC uses UTF-16. However, older
|
||||
EAC logs will often be in a smattering of different encoding (most popular is CP-1251, which
|
||||
is a Cyrillic code page), which are in-compatible with UTF-8 based analysis, and so require
|
||||
decoding first. Due to the difficulty of this problem, we use chardet (if installed) to give
|
||||
us the encoding if we cannot detect it via a BOM.
|
||||
|
||||
If no [out_file] is specified, the decoded log will be printed to stdout.
|
||||
HELP
|
||||
)
|
||||
->addArgument('file', InputArgument::REQUIRED, 'Log file to decode')
|
||||
->addArgument('out_file', InputArgument::OPTIONAL, 'File to write decoded log file to');
|
||||
}
|
||||
|
||||
protected function execute(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
$filename = $input->getArgument('file');
|
||||
if (!file_exists($filename)) {
|
||||
$output->writeln("Invalid file");
|
||||
return 1;
|
||||
}
|
||||
|
||||
$log = file_get_contents($filename);
|
||||
$log = Util::decodeEncoding($log, $filename);
|
||||
|
||||
if ($input->getArgument('out_file')) {
|
||||
file_put_contents($input->getArgument('out_file'), $log);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
53
src/Command/TranslateCommand.php
Normal file
53
src/Command/TranslateCommand.php
Normal file
@@ -0,0 +1,53 @@
|
||||
<?php
|
||||
|
||||
namespace OrpheusNET\Logchecker\Command;
|
||||
|
||||
use OrpheusNET\Logchecker\Parser\EAC\Translator;
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Input\InputArgument;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
|
||||
class TranslateCommand extends Command
|
||||
{
|
||||
protected function configure()
|
||||
{
|
||||
$this
|
||||
->setName('translate')
|
||||
->setDescription('Translates a log into english')
|
||||
->setHelp("Translates a log into english")
|
||||
->addOption('language', 'l', InputOption::VALUE_OPTIONAL, 'Force language to use')
|
||||
->addArgument('file', InputArgument::REQUIRED, 'Log file to decode')
|
||||
->addArgument('out_file', InputArgument::OPTIONAL, 'File to write decoded log file to');
|
||||
}
|
||||
|
||||
protected function execute(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
$filename = $input->getArgument('file');
|
||||
if (!file_exists($filename)) {
|
||||
$output->writeln("Invalid file");
|
||||
return 1;
|
||||
}
|
||||
|
||||
$log = file_get_contents($filename);
|
||||
if ($input->getOption('language')) {
|
||||
$code = $input->getOption('language');
|
||||
$output->writeln("Translating from {$code} to English");
|
||||
} else {
|
||||
$language = Translator::getLanguage($log);
|
||||
$code = $language['code'];
|
||||
$output->writeln("Translating from {$language['name']} ({$language['name_english']}) to English");
|
||||
}
|
||||
|
||||
$log = Translator::translate($log, $language['code']);
|
||||
|
||||
if ($input->getArgument('out_file')) {
|
||||
file_put_contents($input->getArgument('out_file'), $log);
|
||||
} else {
|
||||
$output->write($log);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
namespace OrpheusNET\Logchecker;
|
||||
|
||||
use OrpheusNET\Logchecker\Checks\Ripper;
|
||||
use OrpheusNET\Logchecker\Check\Ripper;
|
||||
use OrpheusNET\Logchecker\Parser\EAC\Translator;
|
||||
use Symfony\Component\Yaml\Yaml;
|
||||
use Symfony\Component\Yaml\Exception\ParseException;
|
||||
@@ -17,7 +17,7 @@ class Logchecker
|
||||
private $logPath = null;
|
||||
private $logs = array();
|
||||
private $Tracks = array();
|
||||
private $checksumStatus = Checks\ChecksumStates::CHECKSUM_OK;
|
||||
private $checksumStatus = Check\ChecksumStates::CHECKSUM_OK;
|
||||
private $Score = 100;
|
||||
private $Details = array();
|
||||
private $Offsets = array();
|
||||
@@ -37,7 +37,6 @@ class Logchecker
|
||||
private $Range = null;
|
||||
private $ARSummary = null;
|
||||
private $XLDSecureRipper = false;
|
||||
private $Chardet = null;
|
||||
private $FakeDrives = [
|
||||
'Generic DVD-ROM SCSI CdRom Device'
|
||||
];
|
||||
@@ -46,13 +45,6 @@ class Logchecker
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
try {
|
||||
$this->Chardet = new Chardet();
|
||||
} catch (\Exception $exc) {
|
||||
// Could not find chardet
|
||||
$this->Chardet = null;
|
||||
}
|
||||
|
||||
$this->AllDrives = array_map(function ($elem) {
|
||||
return explode(',', $elem);
|
||||
}, file(__DIR__ . '/offsets.txt', FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES));
|
||||
@@ -78,7 +70,7 @@ class Logchecker
|
||||
$this->logPath = null;
|
||||
$this->logs = array();
|
||||
$this->Tracks = array();
|
||||
$this->checksumStatus = Checks\ChecksumStates::CHECKSUM_OK;
|
||||
$this->checksumStatus = Check\ChecksumStates::CHECKSUM_OK;
|
||||
$this->Score = 100;
|
||||
$this->Details = array();
|
||||
$this->Offsets = array();
|
||||
@@ -104,31 +96,6 @@ class Logchecker
|
||||
$this->ValidateChecksum = $Bool;
|
||||
}
|
||||
|
||||
private function convertEncoding()
|
||||
{
|
||||
// Whipper uses UTF-8 so we don't need to bother checking, especially as it's
|
||||
// possible a log may be falsely detected as a different encoding by chardet
|
||||
if (strpos($this->log, "Log created by: whipper") !== false) {
|
||||
return;
|
||||
}
|
||||
// To parse the log, we want to deal with the log in UTF-8. EAC by default should
|
||||
// always output to UTF-16 and XLD to UTF-8, but sometimes people view the log and
|
||||
// re-encode them to something else (like Windows-1251), and we need to use chardet
|
||||
// to detect this so we can then convert it to UTF-8.
|
||||
if (ord($this->log[0]) . ord($this->log[1]) == 0xFF . 0xFE) {
|
||||
$this->log = mb_convert_encoding(substr($this->log, 2), 'UTF-8', 'UTF-16LE');
|
||||
} elseif (ord($this->log[0]) . ord($this->log[1]) == 0xFE . 0xFF) {
|
||||
$this->log = mb_convert_encoding(substr($this->log, 2), 'UTF-8', 'UTF-16BE');
|
||||
} elseif (ord($this->log[0]) == 0xEF && ord($this->log[1]) == 0xBB && ord($this->log[2]) == 0xBF) {
|
||||
$this->log = substr($this->log, 3);
|
||||
} elseif ($this->Chardet !== null) {
|
||||
$Results = $this->Chardet->analyze($this->logPath);
|
||||
if ($Results['charset'] !== 'utf-8' && $Results['confidence'] > 0.7) {
|
||||
$this->log = mb_convert_encoding($this->log, 'UTF-8', $Results['charset']);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array Returns an array that contains [Score, Details, Checksum, Log]
|
||||
*/
|
||||
@@ -136,7 +103,7 @@ class Logchecker
|
||||
{
|
||||
|
||||
try {
|
||||
$this->convertEncoding();
|
||||
$this->log = Util::decodeEncoding($this->log, $this->logPath);
|
||||
} catch (\Exception $exc) {
|
||||
$this->Score = 0;
|
||||
$this->account('Could not detect log encoding, log is corrupt.');
|
||||
@@ -186,7 +153,7 @@ class Logchecker
|
||||
$Class = $this->checksumStatus ? 'good' : 'bad';
|
||||
$Yaml['SHA-256 hash'] = "<span class='{$Class}'>{$Hash}</span>";
|
||||
} else {
|
||||
$this->checksumStatus = Checks\ChecksumStates::CHECKSUM_MISSING;
|
||||
$this->checksumStatus = Check\ChecksumStates::CHECKSUM_MISSING;
|
||||
}
|
||||
|
||||
$RippingKey = 'Ripping phase information';
|
||||
@@ -356,7 +323,7 @@ class Logchecker
|
||||
PREG_SPLIT_DELIM_CAPTURE
|
||||
);
|
||||
} else { //no checksum
|
||||
$this->checksumStatus = Checks\ChecksumStates::CHECKSUM_MISSING;
|
||||
$this->checksumStatus = Check\ChecksumStates::CHECKSUM_MISSING;
|
||||
$this->logs = preg_split("/(\nEnd of status report)/i", $this->log, -1, PREG_SPLIT_DELIM_CAPTURE);
|
||||
foreach ($this->logs as $Key => $Value) {
|
||||
if (preg_match("/---- CUETools DB Plugin V.+/i", $Value)) {
|
||||
@@ -370,7 +337,7 @@ class Logchecker
|
||||
if ($Log === "" || preg_match('/^\-+$/i', $Log)) {
|
||||
unset($this->logs[$Key]);
|
||||
} elseif (
|
||||
$this->checksumStatus !== Checks\ChecksumStates::CHECKSUM_OK
|
||||
$this->checksumStatus !== Check\ChecksumStates::CHECKSUM_OK
|
||||
&& preg_match("/End of status report/i", $Log)
|
||||
) {
|
||||
//strip empty
|
||||
@@ -378,13 +345,13 @@ class Logchecker
|
||||
$this->logs[$Key - 1] .= $Log;
|
||||
unset($this->logs[$Key]);
|
||||
} elseif (
|
||||
$this->checksumStatus === Checks\ChecksumStates::CHECKSUM_OK
|
||||
$this->checksumStatus === Check\ChecksumStates::CHECKSUM_OK
|
||||
&& preg_match("/[\=]+\s+Log checksum/i", $Log)
|
||||
) {
|
||||
$this->logs[$Key - 1] .= $Log;
|
||||
unset($this->logs[$Key]);
|
||||
} elseif (
|
||||
$this->checksumStatus === Checks\ChecksumStates::CHECKSUM_OK
|
||||
$this->checksumStatus === Check\ChecksumStates::CHECKSUM_OK
|
||||
&& preg_match("/[\-]+BEGIN XLD SIGNATURE/i", $Log)
|
||||
) {
|
||||
$this->logs[$Key - 1] .= $Log;
|
||||
@@ -404,7 +371,7 @@ class Logchecker
|
||||
if ($Matches[1]) {
|
||||
$this->version = floatval(explode(" ", substr($Matches[1], 1))[0]);
|
||||
if ($this->version < 1) {
|
||||
$this->checksumStatus = Checks\ChecksumStates::CHECKSUM_MISSING;
|
||||
$this->checksumStatus = Check\ChecksumStates::CHECKSUM_MISSING;
|
||||
if ($this->version <= 0.95) {
|
||||
# EAC 0.95 and before was missing a handful of stuff for full log validation
|
||||
# that 0.99 included (-30 points)
|
||||
@@ -412,14 +379,14 @@ class Logchecker
|
||||
}
|
||||
} else {
|
||||
// Above version 1 and no checksum
|
||||
$this->checksumStatus = Checks\ChecksumStates::CHECKSUM_MISSING;
|
||||
$this->checksumStatus = Check\ChecksumStates::CHECKSUM_MISSING;
|
||||
}
|
||||
} else {
|
||||
$this->checksumStatus = Checks\ChecksumStates::CHECKSUM_MISSING;
|
||||
$this->checksumStatus = Check\ChecksumStates::CHECKSUM_MISSING;
|
||||
$this->account("EAC version older than 0.99", 30);
|
||||
}
|
||||
} elseif (preg_match('/EAC extraction logfile from/i', $Log)) {
|
||||
$this->checksumStatus = Checks\ChecksumStates::CHECKSUM_MISSING;
|
||||
$this->checksumStatus = Check\ChecksumStates::CHECKSUM_MISSING;
|
||||
$this->account("EAC version older than 0.99", 30);
|
||||
}
|
||||
|
||||
@@ -433,7 +400,7 @@ class Logchecker
|
||||
if (preg_match('/X Lossless Decoder version (\d+) \((.+)\)/i', $Log, $Matches)) { //xld version & checksum
|
||||
$this->version = $Matches[1];
|
||||
if ($this->version >= 20121222 && !$Count) {
|
||||
$this->checksumStatus = Checks\ChecksumStates::CHECKSUM_MISSING;
|
||||
$this->checksumStatus = Check\ChecksumStates::CHECKSUM_MISSING;
|
||||
//$this->account('No checksum with XLD 20121222 or newer', 15);
|
||||
}
|
||||
}
|
||||
@@ -482,11 +449,11 @@ class Logchecker
|
||||
|
||||
if (
|
||||
$this->ValidateChecksum
|
||||
&& $this->checksumStatus == Checks\ChecksumStates::CHECKSUM_OK
|
||||
&& $this->checksumStatus == Check\ChecksumStates::CHECKSUM_OK
|
||||
&& !empty($this->logPath)
|
||||
) {
|
||||
if (Checks\Checksum::logcheckerExists($EAC)) {
|
||||
$this->checksumStatus = Checks\Checksum::validate($this->logPath, $EAC);
|
||||
if (Check\Checksum::logcheckerExists($EAC)) {
|
||||
$this->checksumStatus = Check\Checksum::validate($this->logPath, $EAC);
|
||||
} else {
|
||||
$this->account(
|
||||
"Could not find {$this->ripper} logchecker, checksum not validated.",
|
||||
|
||||
@@ -16,9 +16,11 @@ class LogcheckerConsole extends Application
|
||||
$analyze_command = new Command\AnalyzeCommand();
|
||||
|
||||
$this->addCommands([
|
||||
$analyze_command
|
||||
$analyze_command,
|
||||
new Command\DecodeCommand(),
|
||||
new Command\TranslateCommand()
|
||||
]);
|
||||
|
||||
$this->setDefaultCommand($analyze_command->getName(), true);
|
||||
//$this->setDefaultCommand($analyze_command->getName(), false);
|
||||
}
|
||||
}
|
||||
|
||||
171
src/Parser/EAC/languages/co.json
Normal file
171
src/Parser/EAC/languages/co.json
Normal file
@@ -0,0 +1,171 @@
|
||||
{
|
||||
"31": "Filename will be ignored",
|
||||
"50": "Value out of range !",
|
||||
"51": "Invalid characters !",
|
||||
"52": "Invalid filename !",
|
||||
|
||||
"1200": "Status and Error Messages",
|
||||
"2501": "Track status and errors",
|
||||
"1203": "Possible Errors",
|
||||
"1204": "Create Log",
|
||||
"1210": "Stato intervallo ed errori",
|
||||
"1211": "Intervallo selezionato",
|
||||
"1212": " Timing problem ",
|
||||
"1213": " Suspicious position ",
|
||||
"1214": " Missing samples",
|
||||
"1215": " Too many samples",
|
||||
"1216": " File write error",
|
||||
"1217": " Livello di picco ",
|
||||
"1299": " Extraction speed ",
|
||||
"1218": " Qualità intervallo ",
|
||||
"1219": " CRC ",
|
||||
"1220": " Copia corretta",
|
||||
"1221": " Copy finished",
|
||||
"1227": " Track quality ",
|
||||
"1228": " Copy aborted",
|
||||
"1269": " Nome file ",
|
||||
"1270": " Pre-gap length ",
|
||||
"1271": " Test CRC ",
|
||||
"1272": " Copy CRC ",
|
||||
"1273": " Compressing",
|
||||
"1280": " Track not fully ripped for AccurateRip lookup",
|
||||
"1281": " Accurately ripped (confidence ",
|
||||
"1282": " Not accurately ripped (confidence ",
|
||||
"1283": " Track not present in AccurateRip database",
|
||||
"1330": " Cannot be verified as accurate",
|
||||
"1337": "cannot be verified as accurate",
|
||||
"1331": ", AccurateRip returned",
|
||||
"1332": "(confidence ",
|
||||
"1333": "No tracks could be verified as accurate",
|
||||
"1334": "You may have a different pressing from the one(s) in the database",
|
||||
"1335": "Some tracks could not be verified as accurate",
|
||||
"1336": "All tracks accurately ripped",
|
||||
"1338": "Null samples used in CRC calculations",
|
||||
"1339": "track(s) not present in the AccurateRip database",
|
||||
"1340": "track(s) accurately ripped",
|
||||
"1341": "track(s) could not be verified as accurate",
|
||||
"1342": "track(s) not fully ripped for AccurateRip lookup",
|
||||
"1343": "track(s) canceled",
|
||||
"1344": "None of the tracks are present in the AccurateRip database",
|
||||
"1284": "Not all tracks ripped accurately",
|
||||
"1222": "Non soNo stati riscontrati errori",
|
||||
"1223": "Review Range",
|
||||
"1224": "There were errors",
|
||||
"1225": "Fine del resoconto di stato",
|
||||
"1321": "Not detected, thus appended to previous track",
|
||||
"1322": "Appended to previous track",
|
||||
"1323": "Appended to next track",
|
||||
"1325": "Log checksum",
|
||||
"1226": "Track",
|
||||
"1230": "Index",
|
||||
"1229": "Review Tracks",
|
||||
"1274": "Estrazione file di log EAC da ",
|
||||
"1240": "January",
|
||||
"1241": "February",
|
||||
"1242": "March",
|
||||
"1243": "April",
|
||||
"1244": "May",
|
||||
"1245": "June",
|
||||
"1246": "July",
|
||||
"1247": "August",
|
||||
"1248": "September",
|
||||
"1249": "October",
|
||||
"1250": "November",
|
||||
"1251": "December",
|
||||
"1232": "EAC extraction log file",
|
||||
"1233": "Unità predefinita: ",
|
||||
"1234": "Modalità di lettura",
|
||||
"1235": "Burst",
|
||||
"1236": "Fast",
|
||||
"1237": "Paranoid",
|
||||
"1238": "Secure with NO C2, accurate stream, NO disable cache",
|
||||
"1239": "Secure with NO C2, NO accurate stream, disable cache",
|
||||
"1252": "Secure with C2, accurate stream, NO disable cache",
|
||||
"1253": "Secure with C2, accurate stream, disable cache",
|
||||
"1254": "Secure with NO C2, accurate stream, disable cache",
|
||||
"1255": "Combined read/write offset correction",
|
||||
"1256": "Correzione offset di lettura",
|
||||
"1257": "Sovrascrivi anche nel Lead-In e Lead-Out",
|
||||
"1258": "Formato di destinazione scelto",
|
||||
"1259": "Additional command line options",
|
||||
"1260": "Routine interne WAV",
|
||||
"1261": "44.100 Hz; 16 Bit; Stereo",
|
||||
"1262": "Use compression offset",
|
||||
"1263": "Altre opzioni : ",
|
||||
"1264": "Riempi sample offset mancanti con silenzio",
|
||||
"1265": "Rimuovi blocchi di silezio ad inizio e fine",
|
||||
"1266": "Normalize to",
|
||||
"13303": "Native Win32 interface for XP/Vista/Win 7",
|
||||
"1267": "Native Win32 interface for Win NT & 2000",
|
||||
"1268": "Interfaccia esterna ASPI (installata)",
|
||||
"1275": "AccurateRip summary",
|
||||
"1276": "not ripped completely",
|
||||
"1277": "accurately ripped (confidence ",
|
||||
"1278": "not ripped accurately (confidence ",
|
||||
"1279": "not present in database",
|
||||
"1285": ", but should be",
|
||||
"1286": "Performing a test extraction only",
|
||||
"1287": "Sectors",
|
||||
"1288": "Exact Audio Copy",
|
||||
"1289": "TOC of the extracted CD",
|
||||
"1290": "Track",
|
||||
"1291": "Start",
|
||||
"1292": "Length",
|
||||
"1293": "Start sector",
|
||||
"1294": "End sector",
|
||||
"1295": "Secure",
|
||||
"1296": "Make use of C2 pointers",
|
||||
"1297": "Utilize accurate stream",
|
||||
"1298": "Defeat audio cache",
|
||||
"1305": "Used interface",
|
||||
"1306": "Command line compressor",
|
||||
"1307": "Selected bitrate",
|
||||
"1308": "Quality",
|
||||
"1328": "High",
|
||||
"1329": "Low",
|
||||
"1309": "Add ID3 tag",
|
||||
"1310": "Sample format",
|
||||
"1320": "Gap handling",
|
||||
"1324": "Left out",
|
||||
|
||||
"81700": "L3Enc MP3 Encoder & Compatible",
|
||||
"81701": "Fraunhofer MP3Enc MP3 Encoder",
|
||||
"81702": "Xing X3Enc MP3 Encoder",
|
||||
"81703": "Xing ToMPG MP3 Encoder",
|
||||
"81704": "LAME MP3 Encoder",
|
||||
"81705": "GOGO MP3 Encoder",
|
||||
"81706": "MPC Encoder",
|
||||
"81707": "Ogg Vorbis Encoder",
|
||||
"81708": "Microsoft WMA9 Encoder",
|
||||
"81709": "FAAC AAC Encoder",
|
||||
"81710": "Homeboy AAC Encoder",
|
||||
"81711": "Quartex AAC Encoder",
|
||||
"81712": "PsyTEL AAC Encoder",
|
||||
"81713": "MBSoft AAC Encoder",
|
||||
"81714": "Yamaha VQF Encoder",
|
||||
"81715": "Real Audio Encoder",
|
||||
"81716": "Monkey's Audio Lossless Encoder",
|
||||
"81717": "Shorten Lossless Encoder",
|
||||
"81718": "RKAU Lossless Encoder",
|
||||
"81719": "LPAC Lossless Encoder",
|
||||
"81720": "User Defined Encoder",
|
||||
|
||||
"1000000": "per CD",
|
||||
|
||||
"4270": "Low",
|
||||
"4271": "Medium",
|
||||
"4272": "High",
|
||||
|
||||
"1": "Corsu",
|
||||
"2": "Corsican",
|
||||
|
||||
"5": "Error Message",
|
||||
"6": "Warning",
|
||||
"7": "Success",
|
||||
"8": "Information",
|
||||
"10": "OK",
|
||||
"11": "Cancel",
|
||||
"12": "Apply",
|
||||
"15": "Yes",
|
||||
"16": "No"
|
||||
}
|
||||
@@ -6,6 +6,13 @@
|
||||
"name": "Български",
|
||||
"name_english": "Bulgarian"
|
||||
},
|
||||
"co": {
|
||||
"eac_strings": [
|
||||
"Estrazione file di log EAC da"
|
||||
],
|
||||
"name": "Corsu",
|
||||
"name_english": "Corsican"
|
||||
},
|
||||
"cs": {
|
||||
"eac_strings": [
|
||||
"Protokol extrakce EAC z "
|
||||
|
||||
32
src/Util.php
32
src/Util.php
@@ -11,4 +11,36 @@ class Util
|
||||
exec("{$where} {$cmd} 2>/dev/null", $output, $return_var);
|
||||
return $return_var === 0;
|
||||
}
|
||||
|
||||
public static function decodeEncoding(string $log, string $logPath): string
|
||||
{
|
||||
try {
|
||||
$chardet = new Chardet();
|
||||
} catch (\RuntimeException $exc) {
|
||||
$chardet = null;
|
||||
}
|
||||
|
||||
// Whipper uses UTF-8 so we don't need to bother checking, especially as it's
|
||||
// possible a log may be falsely detected as a different encoding by chardet
|
||||
if (strpos($log, "Log created by: whipper") !== false) {
|
||||
return $log;
|
||||
}
|
||||
// To parse the log, we want to deal with the log in UTF-8. EAC by default should
|
||||
// always output to UTF-16 and XLD to UTF-8, but sometimes people view the log and
|
||||
// re-encode them to something else (like Windows-1251), and we need to use chardet
|
||||
// to detect this so we can then convert it to UTF-8.
|
||||
if (ord($log[0]) . ord($log[1]) == 0xFF . 0xFE) {
|
||||
$log = mb_convert_encoding(substr($log, 2), 'UTF-8', 'UTF-16LE');
|
||||
} elseif (ord($log[0]) . ord($log[1]) == 0xFE . 0xFF) {
|
||||
$log = mb_convert_encoding(substr($log, 2), 'UTF-8', 'UTF-16BE');
|
||||
} elseif (ord($log[0]) == 0xEF && ord($log[1]) == 0xBB && ord($log[2]) == 0xBF) {
|
||||
$log = substr($log, 3);
|
||||
} elseif ($chardet !== null) {
|
||||
$Results = $chardet->analyze($logPath);
|
||||
if ($Results['charset'] !== 'utf-8' && $Results['confidence'] > 0.7) {
|
||||
$log = mb_convert_encoding($log, 'UTF-8', $Results['charset']);
|
||||
}
|
||||
}
|
||||
return $log;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,10 +2,10 @@
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace OrpheusNET\Logchecker\Checks;
|
||||
namespace OrpheusNET\Logchecker\Check;
|
||||
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use OrpheusNET\Logchecker\Checks\Ripper;
|
||||
use OrpheusNET\Logchecker\Check\Ripper;
|
||||
use OrpheusNET\Logchecker\Exception\UnknownRipperException;
|
||||
|
||||
class RipperTest extends TestCase
|
||||
@@ -18,7 +18,12 @@ class RipperTest extends TestCase
|
||||
Ripper::EAC
|
||||
],
|
||||
[
|
||||
"EAC 展開 ログファイル 日付: 24. 12月 2005, 18:37 for CD",
|
||||
"EAC 展開 ログファイル 日付: 24. 12月 2005, 18:37 for CD\nTest",
|
||||
Ripper::EAC
|
||||
],
|
||||
[
|
||||
"Отчёт EAC об извлечении, выполненном 15. января 2010, 16:06 для диска:\n" .
|
||||
"Girls Against Boys / Cruise Yourself",
|
||||
Ripper::EAC
|
||||
],
|
||||
[
|
||||
|
||||
@@ -13,7 +13,7 @@ class TranslatorTest extends TestCase
|
||||
public function foreignLogDataProvider()
|
||||
{
|
||||
$logs = [];
|
||||
$logPath = implode(DIRECTORY_SEPARATOR, [__DIR__, '..', '..', 'logs', 'transcoded_foreign_logs']);
|
||||
$logPath = implode(DIRECTORY_SEPARATOR, [__DIR__, '..', '..', 'logs', 'eac', 'transcoded_logs']);
|
||||
foreach (new FilesystemIterator($logPath, FilesystemIterator::SKIP_DOTS) as $dir) {
|
||||
if ($dir->isFile()) {
|
||||
continue;
|
||||
|
||||
29
tests/logs/eac/transcoded_logs/co/1.log
Normal file
29
tests/logs/eac/transcoded_logs/co/1.log
Normal file
@@ -0,0 +1,29 @@
|
||||
Estrazione file di log EAC da 13. Giugno 2006, 12:34 per CD
|
||||
Cousteau / Cousteau
|
||||
|
||||
Unità predefinita: HL-DT-STCD-RW GCE-8480B Adapter: 2 ID: 1
|
||||
Modalità di lettura: Sicuro con NO C2, Lettura Accurata, Disattiva Cache
|
||||
Correzione offset di lettura:6
|
||||
Sovrascrivi anche nel Lead-In e Lead-Out : No
|
||||
|
||||
Formato di destinazione scelto: Routine interne WAV
|
||||
44.100 Hz; 16 Bit; Stereo
|
||||
|
||||
Altre opzioni :
|
||||
Riempi sample offset mancanti con silenzio : Sì
|
||||
Rimuovi blocchi di silezio ad inizio e fine : No
|
||||
Interfaccia esterna ASPI (installata)
|
||||
|
||||
|
||||
Stato intervallo ed errori
|
||||
Intervallo selezionato
|
||||
Nome file C:\Documents and Settings\maurizio\Desktop\Cousteau - Cousteau.wav
|
||||
|
||||
Livello di picco 99.9 %
|
||||
Qualità intervallo 100.0 %
|
||||
CRC 5B545F17
|
||||
Copia corretta
|
||||
|
||||
Non sono stati riscontrati errori
|
||||
|
||||
Fine del resoconto di stato
|
||||
29
tests/logs/eac/transcoded_logs/co/1_en.log
Normal file
29
tests/logs/eac/transcoded_logs/co/1_en.log
Normal file
@@ -0,0 +1,29 @@
|
||||
EAC extraction logfile from 13. GiugNo 2006, 12:34 for disc
|
||||
Cousteau / Cousteau
|
||||
|
||||
Used drive : HL-DT-STCD-RW GCE-8480B Adapter: 2 ID: 1
|
||||
Read mode: Sicuro con No C2, Lettura Accurata, Disattiva Cache
|
||||
Read offset correction:6
|
||||
Overread into Lead-In and Lead-Out : No
|
||||
|
||||
Used output format: Internal WAV Routines
|
||||
44.100 Hz; 16 Bit; Stereo
|
||||
|
||||
Other options :
|
||||
Fill up missing offset samples with silence : Sì
|
||||
Delete leading and trailing silent blocks : No
|
||||
Installed external ASPI interface
|
||||
|
||||
|
||||
Range status and errors
|
||||
Selected range
|
||||
Filename C:\Documents and Settings\maurizio\Desktop\Cousteau - Cousteau.wav
|
||||
|
||||
Peak level 99.9 %
|
||||
Range Quality 100.0 %
|
||||
CRC 5B545F17
|
||||
Copy OK
|
||||
|
||||
No errors occurred
|
||||
|
||||
End of status report
|
||||
Reference in New Issue
Block a user