Compare commits

...
17 Commits
Author SHA1 Message Date
itismadness 6298d718b2 Fix some parse bugs with whipper logs 2019-07-24 08:58:56 +03:30
itismadness 4c4490ba3b Release v0.8.4 2019-07-08 05:40:45 +05:30
itismadness 0f9db5c9f5 Subtract 20 points if accurate stream could not be found 2019-07-08 01:53:11 +02:00
itismadness 234de45ab2 Subtract 20 points for logs that do not have accurate stream set to yes 2019-07-08 05:19:11 +05:30
itismadness 7be957b343 Install chardet to travis 2019-06-10 17:31:48 -08:00
itismadness 09bfa6a98b Fix handling of whipper logs under YAML 1.2 2019-06-11 14:13:21 +12:45
itismadness ddbc042897 Update composer dependencies 2019-06-11 03:49:10 +09:00
itismadness 3f81c3a91d Fix sudo usage for installing pip in Travis 2019-02-06 11:11:22 -05:00
itismadness 04d6d9cbef Use get-pip.py to install pip,setuptools,wheel on Travis 2019-02-06 11:06:59 -05:00
itismadness 752ec6af0a Install python3 and pip on Travis 2019-02-06 10:56:13 -05:00
itismadness 594add313f Bump to 0.8.2 2019-02-06 10:47:09 -05:00
Borewit fb05ef7b26 README: fix compile command using relative path (#7)
* Fix compile command using relative path

* Fix example using namespace

* More explicit code type declaration & include autoload
2019-01-02 12:09:53 -05:00
Borewit e462fdef45 #8 Prevent syntax error in unpacking nested arrays into loop variables (#9) 2019-01-02 12:09:38 -05:00
itismadness b38c25a13d Fix breaking when spaces in log name (closes #5) 2018-12-17 10:51:58 -05:00
itismadness bd168e98b1 Bump to 0.8.1 2018-11-29 22:33:32 -05:00
itismadness ec4d49f690 Use command -v for checking for programs 2018-11-29 22:32:33 -05:00
itismadness 5a6a22cfbe Update readme 2018-11-29 21:30:21 -05:00
9 changed files with 175 additions and 81 deletions

No files matched your search

+11 -2
View File
@@ -1,9 +1,10 @@
language: php
sudo: true
dist: trusty
dist: xenial
cache:
directories:
- $HOME/.cache/pip
- $HOME/.composer/cache
php:
@@ -19,11 +20,19 @@ matrix:
- php: nightly
before_install:
- composer install --ansi --prefer-dist --no-interaction --optimize-autoloader --no-suggest --no-progress
- sudo apt-get install python3
- wget https://bootstrap.pypa.io/get-pip.py
- sudo python3 get-pip.py
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
before_deploy:
- php -d phar.readonly=0 bin/compile
+62 -25
View File
@@ -15,39 +15,32 @@ setting up the necessary programs to validate the checksum, see below for the gi
## Requirements
* PHP 7.0+
* Python3.4+
## Optional Requirements
* Python 3.5+
* [chardet](https://github.com/chardet/chardet)
* [eac_logchecker.py](https://github.com/OPSnet/eac_logchecker.py)
* [xld_logchecker.py](https://github.com/OPSnet/xld_logchecker.py)
## Installation
```
$ composer require orpheusnet/logchecker
$ pip3 install chardet eac-logchecker xld-logchecker
```
## Usage
### CLI
## Standalone
### Installation
Go to our [releases](https://github.com/OPSnet/Logchecker/releases) and grab the logchecker.phar
file. Download this file, and then it can executed via CLI by running `php logchecker.phar`.
Alternatively, if you `chmod +x logchecker.phar`, it can be executed directly by doing `./logchecker.phar`.
To install it globally, run:
```bash
mv logchecker.phar /usr/local/bin/logchecker
chmod +x /usr/local/bin/logchecker
```
$ logchecker list
Logchecker by Orpheus 0.5.0
Usage:
command [options] [arguments]
Options:
-h, --help Display this help message
-V, --version Display this application version
Available commands:
analyze analyze log file
help Displays help for a command
list Lists commands
$ logchecker analyze --help
Description:
analyze log file
### Usage
```
$ logchecker --help
Usage:
analyze [options] [--] <file>
@@ -57,11 +50,18 @@ Arguments:
Options:
--output Print the HTML log text
-h, --help Display this help message
-q, --quiet Do not output any message
-V, --version Display this application version
--ansi Force ANSI output
--no-ansi Disable ANSI output
-n, --no-interaction Do not ask any interactive question
-file, --out=OUT File to write HTML log text to
-v|vv|vvv, --verbose Increase the verbosity of messages: 1 for normal output, 2 for more verbose output and 3 for debug
Help:
This command analyzes a log file
$ logchecker analyze tests/logs/wgdbcm.log
$ logchecker tests/logs/wgdbcm.log
Score : 57
Checksum: false
Details :
@@ -75,10 +75,47 @@ Details :
```
### Code
```
```php
<?php
$logchecker = new OrpheusNET\Logchecker\Logchecker();
$logchecker->add_file('path/to/file.log');
list($score, $details, $checksum, $log_text) = $logchecker->parse();
```
## Library Usage
### Installation
```
$ composer require orpheusnet/logchecker
```
### Usage
```php
<?php
require __DIR__ . '/vendor/autoload.php';
use OrpheusNET\Logchecker\Logchecker;
$logchecker = new Logchecker();
$logchecker->new_file('/path/to/log/file');
list($score, $details, $checksum, $log_text) = $logchecker->parse();
print('Score: ' . $score . "\n");
print('Checksum: ' . ($checksum ? 'true' : 'false') . "\n");
print("\nDetails:\n");
foreach ($details as $detail) {
print(" {$detail}\n");
}
print("\nLog Text:\n{$log_text}");
```
## Building
To build your own phar, you can checkout this repository, and then
run the `bin/compile` script. To do this, run the following commands:
```bash
git clone https://github.com/OPSnet/Logchecker
cd Logchecker
composer install
php -d phar.readonly=0 bin/compile
```
+1 -1
View File
@@ -1,7 +1,7 @@
{
"name": "orpheusnet/logchecker",
"description": "Logchecker for validating logs generated from supported ripping programs (like EAC and XLD)",
"version": "0.8.0",
"version": "0.8.5",
"license": "Unlicense",
"type": "library",
"authors": [
Generated
+32 -29
View File
@@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
"content-hash": "165e83b0ccad187ade7bf2a38820cb4c",
"content-hash": "9ad854c65da76498f6a2af058812e332",
"packages": [
{
"name": "psr/log",
@@ -55,16 +55,16 @@
},
{
"name": "symfony/console",
"version": "v3.4.19",
"version": "v3.4.28",
"source": {
"type": "git",
"url": "https://github.com/symfony/console.git",
"reference": "8f80fc39bbc3b7c47ee54ba7aa2653521ace94bb"
"reference": "8e1d1e406dd31727fa70cd5a99cda202e9d6a5c6"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/console/zipball/8f80fc39bbc3b7c47ee54ba7aa2653521ace94bb",
"reference": "8f80fc39bbc3b7c47ee54ba7aa2653521ace94bb",
"url": "https://api.github.com/repos/symfony/console/zipball/8e1d1e406dd31727fa70cd5a99cda202e9d6a5c6",
"reference": "8e1d1e406dd31727fa70cd5a99cda202e9d6a5c6",
"shasum": ""
},
"require": {
@@ -76,6 +76,9 @@
"symfony/dependency-injection": "<3.4",
"symfony/process": "<3.3"
},
"provide": {
"psr/log-implementation": "1.0"
},
"require-dev": {
"psr/log": "~1.0",
"symfony/config": "~3.3|~4.0",
@@ -85,7 +88,7 @@
"symfony/process": "~3.3|~4.0"
},
"suggest": {
"psr/log-implementation": "For using the console logger",
"psr/log": "For using the console logger",
"symfony/event-dispatcher": "",
"symfony/lock": "",
"symfony/process": ""
@@ -120,20 +123,20 @@
],
"description": "Symfony Console Component",
"homepage": "https://symfony.com",
"time": "2018-11-26T12:48:07+00:00"
"time": "2019-05-09T08:42:51+00:00"
},
{
"name": "symfony/debug",
"version": "v3.4.19",
"version": "v3.4.28",
"source": {
"type": "git",
"url": "https://github.com/symfony/debug.git",
"reference": "2016b3eec2e49c127dd02d0ef44a35c53181560d"
"reference": "671fc55bd14800668b1d0a3708c3714940e30a8c"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/debug/zipball/2016b3eec2e49c127dd02d0ef44a35c53181560d",
"reference": "2016b3eec2e49c127dd02d0ef44a35c53181560d",
"url": "https://api.github.com/repos/symfony/debug/zipball/671fc55bd14800668b1d0a3708c3714940e30a8c",
"reference": "671fc55bd14800668b1d0a3708c3714940e30a8c",
"shasum": ""
},
"require": {
@@ -176,20 +179,20 @@
],
"description": "Symfony Debug Component",
"homepage": "https://symfony.com",
"time": "2018-11-11T19:48:54+00:00"
"time": "2019-05-18T13:32:47+00:00"
},
{
"name": "symfony/polyfill-ctype",
"version": "v1.10.0",
"version": "v1.11.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-ctype.git",
"reference": "e3d826245268269cd66f8326bd8bc066687b4a19"
"reference": "82ebae02209c21113908c229e9883c419720738a"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/e3d826245268269cd66f8326bd8bc066687b4a19",
"reference": "e3d826245268269cd66f8326bd8bc066687b4a19",
"url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/82ebae02209c21113908c229e9883c419720738a",
"reference": "82ebae02209c21113908c229e9883c419720738a",
"shasum": ""
},
"require": {
@@ -201,7 +204,7 @@
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.9-dev"
"dev-master": "1.11-dev"
}
},
"autoload": {
@@ -234,20 +237,20 @@
"polyfill",
"portable"
],
"time": "2018-08-06T14:22:27+00:00"
"time": "2019-02-06T07:57:58+00:00"
},
{
"name": "symfony/polyfill-mbstring",
"version": "v1.10.0",
"version": "v1.11.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-mbstring.git",
"reference": "c79c051f5b3a46be09205c73b80b346e4153e494"
"reference": "fe5e94c604826c35a32fa832f35bd036b6799609"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/c79c051f5b3a46be09205c73b80b346e4153e494",
"reference": "c79c051f5b3a46be09205c73b80b346e4153e494",
"url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/fe5e94c604826c35a32fa832f35bd036b6799609",
"reference": "fe5e94c604826c35a32fa832f35bd036b6799609",
"shasum": ""
},
"require": {
@@ -259,7 +262,7 @@
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.9-dev"
"dev-master": "1.11-dev"
}
},
"autoload": {
@@ -293,20 +296,20 @@
"portable",
"shim"
],
"time": "2018-09-21T13:07:52+00:00"
"time": "2019-02-06T07:57:58+00:00"
},
{
"name": "symfony/yaml",
"version": "v3.4.19",
"version": "v3.4.28",
"source": {
"type": "git",
"url": "https://github.com/symfony/yaml.git",
"reference": "291e13d808bec481eab83f301f7bff3e699ef603"
"reference": "212a27b731e5bfb735679d1ffaac82bd6a1dc996"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/yaml/zipball/291e13d808bec481eab83f301f7bff3e699ef603",
"reference": "291e13d808bec481eab83f301f7bff3e699ef603",
"url": "https://api.github.com/repos/symfony/yaml/zipball/212a27b731e5bfb735679d1ffaac82bd6a1dc996",
"reference": "212a27b731e5bfb735679d1ffaac82bd6a1dc996",
"shasum": ""
},
"require": {
@@ -352,7 +355,7 @@
],
"description": "Symfony Yaml Component",
"homepage": "https://symfony.com",
"time": "2018-11-11T19:48:54+00:00"
"time": "2019-03-25T07:48:46+00:00"
}
],
"packages-dev": [],
+1 -1
View File
@@ -44,4 +44,4 @@ for ($i = 1; $i < $rows->length; $i++) {
file_put_contents(__DIR__.'/../src/offsets.txt', implode("\n", $offsets));
print("Updating ".count($offsets)." drives\n");
print("Updating ".count($offsets)." drives\n");
+2 -1
View File
@@ -15,11 +15,12 @@ class Chardet {
foreach ($this->executables as $executable) {
if (Util::commandExists($executable)) {
$this->executable = $executable;
break;
}
}
if ($this->executable === null) {
throw new \RuntimeException('Chardet not installed');
throw new \RuntimeException('chardet not installed');
}
}
+2
View File
@@ -28,6 +28,8 @@ class AnalyzeCommand extends Command {
$logchecker = new Logchecker();
$logchecker->new_file($filename);
list($score, $details, $checksum, $log_text) = $logchecker->parse();
$output->writeln('Ripper : ' . $logchecker->get_ripper());
$output->writeln('Version : ' . $logchecker->get_version());
$output->writeln('Score : ' . $score);
$output->writeln('Checksum: ' . ($checksum ? 'true' : 'false'));
+59 -19
View File
@@ -116,6 +116,11 @@ class Logchecker {
}
private function convert_encoding() {
// 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
@@ -159,14 +164,32 @@ class Logchecker {
}
private function whipper_parse() {
// Whipper 0.7.x has an issue where it can produce invalid YAML
// as it hand writes out the values without dealing properly
// with the escaping the output, so we fix that here
$log = preg_replace_callback('/^ Release: (.+)$/m', function ($match) {
return " Release: ".Yaml::dump($match[1]);
}, $this->Log);
try {
$Yaml = Yaml::parse($this->Log);
$Yaml = Yaml::parse($log);
}
catch (ParseException $exception) {
$this->account('Could not parse whipper log.', 100);
return $this->return_parse();
}
$this->RIPPER = 'whipper';
$this->Version = explode(" ", $Yaml['Log created by'])[1];
// Releases before this used octal numbers for tracks in the log which
// gets messed up in parsing and we lose track data (e.g. tracks 08 and
// 09 get merged into one entry).
if (empty($this->Version) || version_compare('0.7.3', $this->Version) === 1) {
$this->account('Logs must be produced by whipper 0.7.3+', 100);
return $this->return_parse();
}
if (!empty($Yaml['SHA-256 hash'])) {
$Hash = $Yaml['SHA-256 hash'];
$Lines = explode("\n", trim($this->Log));
@@ -217,15 +240,18 @@ class Logchecker {
}
$DefeatCache = $Yaml['Ripping phase information']['Defeat audio cache'];
if ($DefeatCache) {
$Value = 'Yes';
$Class = 'good';
if (is_string($DefeatCache)) {
$Value = (strtolower($DefeatCache) === 'yes') ? 'Yes' : 'No';
$Class = (strtolower($DefeatCache) === 'yes') ? 'good' : 'bad';
}
else {
$Value = 'No';
$Class = 'bad';
$this->account('"Defeat audio cache" should be yes', 10);
$Value = ($DefeatCache === true) ? 'true' : 'false';
$Class = ($DefeatCache === true) ? 'good' : 'bad';
}
if ($Class === 'bad') {
$this->account('"Defeat audio cache" should be Yes/true', 10);
}
$Yaml['Ripping phase information']['Defeat audio cache'] = "<span class='{$Class}'>{$Value}</span>";
foreach ($Yaml['Tracks'] as $Key => $Track) {
@@ -245,7 +271,7 @@ class Logchecker {
$this->Log .= "Ripping phase information:\n";
foreach ($Yaml['Ripping phase information'] as $Key => $Value) {
if (is_bool($Value)) {
$Value = ($Value) ? 'Yes' : 'No';
$Value = ($Value) ? 'true' : 'false';
}
$this->Log .= " {$Key}: {$Value}\n";
}
@@ -254,7 +280,7 @@ class Logchecker {
$this->Log .= "CD metadata:\n";
foreach ($Yaml['CD metadata'] as $Key => $Value) {
if (is_bool($Value)) {
$Value = ($Value) ? 'Yes' : 'No';
$Value = ($Value) ? 'true' : 'false';
}
$this->Log .= " {$Key}: {$Value}\n";
}
@@ -439,10 +465,14 @@ class Logchecker {
$GoodString = 'OK';
}
$CommandExists = Util::commandExists($Command);
$Out = shell_exec("{$Command} {$this->LogPath}");
if (Util::strposArray($Out, $BadStrings) !== false || strpos($Out, $GoodString) === false) {
$this->Checksum = false;
if (Util::commandExists($Command)) {
$Out = shell_exec("{$Command} ".escapeshellarg($this->LogPath));
if ($Out == null || Util::strposArray($Out, $BadStrings) !== false || strpos($Out, $GoodString) === false) {
$this->Checksum = false;
}
}
else {
$this->account("Could not find {$Command}, checksum not validated.", false, false, false, true);
}
}
@@ -494,7 +524,7 @@ class Logchecker {
'accurate_stream_eac_pre99'
), $Log, 1, $EAC_ac_stream_pre99);
if (!$EAC_ac_stream && !$EAC_ac_stream_pre99 && !$this->NonSecureMode && $EAC) {
$this->account('Could not verify accurate stream');
$this->account('Could not verify accurate stream', 20);
}
$Log = preg_replace_callback('/Defeat audio cache( +): (Yes|No)/i', array(
$this,
@@ -1020,7 +1050,7 @@ class Logchecker {
$MatchedDrives[$i] = ['drives' => [], 'offsets' => []];
}
foreach ($this->AllDrives as [$Drive, $Offset]) {
foreach ($this->AllDrives as list($Drive, $Offset)) {
$Distance = levenshtein($Drive, $DriveName);
if ($Distance < 5) {
$MatchedDrives[$Distance]['drives'][] = $Drive;
@@ -1136,18 +1166,20 @@ class Logchecker {
function accurate_stream($Matches)
{
if ($Matches[2] == 'Yes') {
$Class = 'goodish';
$Class = 'good';
} else {
$Class = 'badish';
$Class = 'bad';
$this->account('"Utilize accurate stream" should be yes', 20);
}
return '<span class="log5">Utilize accurate stream' . $Matches[1] . '</span>: <span class="' . $Class . '">' . $Matches[2] . '</span>';
}
function accurate_stream_eac_pre99($Matches)
{
if (strtolower($Matches[1]) != 'no ') {
$Class = 'goodish';
$Class = 'good';
} else {
$Class = 'badish';
$Class = 'bad';
$this->account('"accurate stream" should be yes', 20);
}
return ', <span class="' . $Class . '">' . $Matches[1] . 'accurate stream</span>';
}
@@ -1460,6 +1492,14 @@ class Logchecker {
);
}
function get_ripper() {
return $this->RIPPER;
}
function get_version() {
return $this->Version;
}
public static function get_accept_values() {
return ".txt,.TXT,.log,.LOG";
}
+5 -3
View File
@@ -3,9 +3,11 @@
namespace OrpheusNET\Logchecker;
class Util {
public static function commandExists($cmd) {
$return = shell_exec(sprintf("which %s", escapeshellarg($cmd)));
return !empty($return);
public static function commandExists(string $cmd) {
$where = substr(strtolower(PHP_OS), 0, 3) === 'win' ? 'where' : 'command -v';
exec("{$where} {$cmd} 2>/dev/null", $output, $return_var);
return $return_var === 0;
}
public static function strposArray(string $haystack, array $needles) {