Skip to content

Commit

Permalink
Rewrite the CLI
Browse files Browse the repository at this point in the history
  • Loading branch information
lGuillaume124 committed Feb 5, 2019
1 parent d6ca7d3 commit fde2143
Show file tree
Hide file tree
Showing 10 changed files with 600 additions and 416 deletions.
9 changes: 9 additions & 0 deletions app/Config/bootstrap.php
Original file line number Diff line number Diff line change
Expand Up @@ -97,11 +97,20 @@
* Configures default file logging options
*/
App::uses('CakeLog', 'Log');

CakeLog::config('synchronization', array(
'engine' => 'File',
'types' => array('error', 'critical', 'alert', 'emergency'),
'file' => 'sonerezh-synchronization',
'scopes' => array('synchronization')
));

CakeLog::config('debug', array(
'engine' => 'File',
'types' => array('notice', 'info', 'debug'),
'file' => 'debug',
));

CakeLog::config('error', array(
'engine' => 'File',
'types' => array('warning', 'error', 'critical', 'alert', 'emergency'),
Expand Down
168 changes: 21 additions & 147 deletions app/Console/Command/SonerezhShell.php
Original file line number Diff line number Diff line change
@@ -1,166 +1,40 @@
<?php

App::uses('AppShell', 'Console/Command');
App::uses('Folder', 'Utility');
App::uses('AudioFileManager', 'AudioFileManager');
App::uses('AudioFileScanner', 'AudioFileScanner');
App::uses('Folder', 'Utility');

App::import('Vendor', 'Getid3/getid3');

class SonerezhShell extends AppShell {
class SonerezhShell extends AppShell
{

public $uses = array('Setting', 'Song');
public $uses = array('Setting');
public $tasks = array('Status', 'Sync');

public function getOptionParser() {
$parser = parent::getOptionParser();

$parser->addArgument('path', array(
'help' => 'The absolute path to the file or the folder you want to import.',
'required' => true
$parser->addSubcommands(array(
'status' => array(
'help' => 'Return the synchronization status.',
'parser' => $this->Status->getOptionParser()
),
'sync' => array(
'help' => 'Manages synchronization (import, update and cleaning).',
'parser' => $this->Sync->getOptionParser()
)
));

$parser->addOption('recursive', array(
'short' => 'r',
'help' => 'Import a folder, recursively.',
'boolean' => true
))->command('import');

return $parser;
}

public function import() {
$path = $this->args[0];
$recursive = $this->param('recursive');
//$verbose = $this->param('verbose');

if (Cache::read('import')) {
$this->out("<warning>[WARN]</warning> The import process is already running via another client or the CLI. You can click on \"Clear cache\" on the settings page to remove the lock, if needed.");
exit(0);
}

$found = array();

if (is_dir($path)) {
$path = new Folder($path);
$this->out("<info>[INFO]</info> Scan $path->path...");

if ($recursive) {
$found = $path->findRecursive('^.*\.(mp3|ogg|flac|aac)$');
} else {
$found = $path->find('^.*\.(mp3|ogg|flac|aac)$');
// The Folder::find() method does not return the absolute path of each file, we need to add it:
$found = preg_filter('/^/', $path->path, $found);
}

} elseif (file_exists($path)) {
$found = array($path);

} else {
$this->error('Invalid path');
}

$already_imported = $this->Song->find('list', array(
'fields' => array('Song.id', 'Song.source_path')
));

$to_import = array_merge(array_diff($found, $already_imported));
$to_import_count = count($to_import);
$found_count = count($found);

if ($to_import_count == 1) {
$selection = $this->in("[INFO] You asked to import $to_import[0]. Continue?", array(
'yes',
'no'
), 'yes');

} elseif ($to_import_count > 1) {
$diff = $found_count - $to_import_count;
$selection = $this->in("[INFO] Found $to_import_count audio files ($diff already in the database). Continue?", array(
'yes',
'no'
), 'yes');

} elseif ($found_count > 0 && $to_import_count == 0) {
$this->out("<info>[INFO]</info> $found_count file(s) found, but already in the database.");
exit(0);

} else {
$this->out('<info>[INFO]</info> Nothing to do.');
exit(0);
}

if ($selection == 'no') {
$this->out('<info>[INFO]</info> Ok, bye.');
exit(0);
}

$this->out('<info>[INFO]</info> Run import', 0);

// Write lock to avoid multiple import processes in the same time
if (Cache::read('import')) {
$this->out("<warning>[WARN]</warning> The import process is already running via another client or the CLI. You can click on \"Clear cache\" on the settings page to remove the lock, if needed.");
exit(0);
} else {
Cache::write('import', true);

// Catch SIGINT
pcntl_signal(SIGINT, function() {
Cache::delete('import');
$this->refreshSyncToken();
exit();
});

$i = 1;
foreach ($to_import as $file) {

pcntl_signal_dispatch();
$song_manager = new AudioFileManager($file);
$parse_result = $song_manager->parse();

if ($parse_result['status'] != 'OK') {
if ($parse_result['status'] == 'WARN') {
$this->overwrite("<warning>[WARN]</warning>[$file] - " . $parse_result['message']);
} elseif ($parse_result['status'] == 'ERR') {
$this->overwrite("<error>[ERR]</error>[$file] - " . $parse_result['message']);
}
}

$this->Song->create();
$status = false;
$message = "<error>[ERR]</error>[$file] - Unable to save the song metadata to the database";
try {
$status = $this->Song->save($parse_result['data']);
}
catch (\Exception $e) {
$message = $e->getMessage();
}
if (!$status) {
$this->overwrite($message);
}

// Progressbar
$percent_done = 100 * $i / $to_import_count;
$hashtags_quantity = round(45 * $percent_done / 100);
$remaining_spaces = 45 - $hashtags_quantity;

if ($i < ($to_import_count)) {
$this->overwrite('<info>[INFO]</info> Run import: [' . round($percent_done) . '%] [' . str_repeat('#', $hashtags_quantity) . str_repeat(' ', $remaining_spaces) . ']', 0);
} else {
$this->overwrite('<info>[INFO]</info> Run import: [' . round($percent_done) . '%] [' . str_repeat('#', $hashtags_quantity) . str_repeat(' ', $remaining_spaces) . ']');
}

$i++;
}

// Delete lock
Cache::delete('import');
$this->refreshSyncToken();
}
}

public function refreshSyncToken() {
// Update the sync_token to refresh the IndexedDB on the browser side
$settings = $this->Setting->find('first');
$settings['Setting']['sync_token'] = time();
$this->Setting->save($settings);
/**
* Override the _welcome parent method to remove the default CakePHP shell
* header.
*/
protected function _welcome()
{
}
}
54 changes: 54 additions & 0 deletions app/Console/Command/Task/StatusTask.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
<?php

/**
* The Status task handles getting information about the synchronization status.
*/
class StatusTask extends AppShell
{
public $uses = array('Track');

public function execute ()
{
$this->cleanNotImportedTracks(); // Clean previous failed import
$scanner = new AudioFileScanner();
$scan = $scanner->scan($new = true, $orphans = true, $outdated = true, $batch = 0);

$data = array(
'to_import' => count($scan['to_import']),
'to_update' => count($scan['to_update']),
'to_remove' => count($scan['to_remove'])
);

if ($this->param('json')) {
$this->out(json_encode($data));
} else {
foreach ($data as $k => $v) {
$label = str_replace('_', ' ', ucfirst($k));
$this->out("$label: $v file(s)");
}
}
}

private function cleanNotImportedTracks()
{
$this->Track->deleteAll(array('imported' => false));
}

/**
* Gets the option parser instance and configures it.
*
* @return ConsoleOptionParser
*/
public function getOptionParser()
{
$parser = parent::getOptionParser();

$parser->addOption('json', array(
'short' => 'j',
'help' => 'Enable JSON output.',
'boolean' => true
));

return $parser;
}
}
Loading

0 comments on commit fde2143

Please sign in to comment.