Skip to content

Commit

Permalink
Rewrite the synchronization process (implement #348)
Browse files Browse the repository at this point in the history
  • Loading branch information
lGuillaume124 committed Feb 5, 2019
1 parent aa9b594 commit d6ca7d3
Show file tree
Hide file tree
Showing 14 changed files with 11,982 additions and 351 deletions.
2 changes: 1 addition & 1 deletion app/Config/bootstrap.php
Original file line number Diff line number Diff line change
Expand Up @@ -121,4 +121,4 @@
define('RESIZED_DIR', IMAGES.'resized'.DS);
define('AVATARS_DIR', 'avatars');
define('DOCKER', false);
define('SYNC_BATCH_SIZE', 100);
define('SYNC_BATCH_SIZE', 50);
35 changes: 20 additions & 15 deletions app/Config/routes.php
Original file line number Diff line number Diff line change
Expand Up @@ -24,36 +24,41 @@
* its action called 'display', and we pass a param to select the view file
* to use (in this case, /app/View/Pages/home.ctp)...
*/
Router::connect('/', array('controller' => 'songs', 'action' => 'index'));
Router::connect('/', array('controller' => 'songs', 'action' => 'index'));

Router::connect('/install', array('controller' => 'installers', 'action' => 'index'));
Router::connect('/docker-install', array('controller' => 'installers', 'action' => 'docker'));
Router::connect('/install', array('controller' => 'installers', 'action' => 'index'));
Router::connect('/docker-install', array('controller' => 'installers', 'action' => 'docker'));

Router::connect('/login', array('controller' => 'users', 'action' => 'login'));
Router::connect('/logout', array('controller' => 'users', 'action' => 'logout'));
Router::connect('/login', array('controller' => 'users', 'action' => 'login'));
Router::connect('/logout', array('controller' => 'users', 'action' => 'logout'));

Router::connect('/api/*', array('controller' => 'api'));
Router::connect('/api/*', array('controller' => 'api'));

Router::connect('/playlists/:action/:id', array('controller' => 'playlists'), array('pass' => array('id')));
Router::connect('/playlists/add', array('controller' => 'playlists', 'action' => 'add'));
Router::connect('/playlists/*', array('controller' => 'playlists', 'action' => 'index'));
Router::connect('/playlists/:action/:id', array('controller' => 'playlists'), array('pass' => array('id')));
Router::connect('/playlists/add', array('controller' => 'playlists', 'action' => 'add'));
Router::connect('/playlists/*', array('controller' => 'playlists', 'action' => 'index'));

Router::connect('/users', array('controller' => 'users', 'action' => 'index'));
Router::connect('/users', array('controller' => 'users', 'action' => 'index'));

Router::connect('/settings', array('controller' => 'settings', 'action' => 'index'));
Router::connect('/settings', array('controller' => 'settings', 'action' => 'index'));

Router::connect('/img/**', array('controller' => 'img', 'action' => 'index'));
Router::connect('/sync', array('controller' => 'sync', 'action' => 'index', '[method]' => 'GET'));
Router::connect('/sync', array('controller' => 'sync', 'action' => 'patchSync', '[method]' => 'PATCH'));
Router::connect('/sync', array('controller' => 'sync', 'action' => 'postSync', '[method]' => 'POST'));
Router::connect('/sync', array('controller' => 'sync', 'action' => 'deleteSync', '[method]' => 'DELETE'));

Router::connect('/:action', array('controller' => 'songs'));
Router::connect('/img/**', array('controller' => 'img', 'action' => 'index'));

Router::connect('/:action', array('controller' => 'songs'));

/**
* Load all plugin routes. See the CakePlugin documentation on
* how to customize the loading of plugin routes.
*/
CakePlugin::routes();
CakePlugin::routes();

/**
* Load the CakePHP default routes. Only remove this if you do not want to use
* the built-in default routes.
*/
require CAKE . 'Config' . DS . 'routes.php';
require CAKE . 'Config' . DS . 'routes.php';
6 changes: 3 additions & 3 deletions app/Console/Command/SonerezhShell.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

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

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

Expand Down Expand Up @@ -113,8 +113,8 @@ public function import() {
foreach ($to_import as $file) {

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

if ($parse_result['status'] != 'OK') {
if ($parse_result['status'] == 'WARN') {
Expand Down
109 changes: 109 additions & 0 deletions app/Controller/Component/ScanComponent.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
<?php

App::uses('Component', 'Controller');

class ScanComponent extends Component
{
/**
* Browse the filesystem to find audio files.
*
* @param bool $new The function will search for audio files that have not been saved yet, or skip them
* otherwise.
* @param bool $orphans The function will search for audio files that exist in the database, but not on the
* filesystem, or skip them otherwise.
* @param bool $outdated The function will search for audio files that have been modified on the filesystem since
* the last synchronization, or skip them otherwise.
* @param int $batch The maximum size of the response array. Unlimited if set to 0 or less.
* @return array
*/
public function scan($new = true, $orphans = false, $outdated = false, $batch = SYNC_BATCH_SIZE)
{
if ($batch <= 0) {
$batch = false;
}

$data = array(
'imported' => array(),
'to_import' => array(),
'to_update' => array(),
'to_remove' => array()
);
$Track = ClassRegistry::init('Track');
$Rootpath = ClassRegistry::init('Rootpath');
$rootpaths = $Rootpath->find('list', array(
'fields' => 'rootpath'
));

if (empty($rootpaths)) {
return $data;
}

$imported = $Track->find('all', array(
'fields' => array('id', 'source_path', 'updated')
));

$importedPaths = array();
$importedUpdates = array();
foreach ($imported as $value) {
$importedPaths[$value['Track']['source_path']] = $value['Track']['id'];
$importedUpdates[$value['Track']['id']] = $value['Track']['updated'];
}

App::uses('Folder', 'Utility');
foreach ($rootpaths as $rootpath) {
$folder = new Folder($rootpath);
$tree = $folder->tree();

foreach ($tree[0] as $directory) {
$directory = new Folder($directory);

// Skip symlinks to avoid infinite loops
if (is_link($directory->path)) {
continue;
}

$foundInThisDirectory = $directory->find('^.*\.(mp3|ogg|flac|aac)$');
if (count($foundInThisDirectory) == 0) {
continue;
}

foreach ($foundInThisDirectory as $key => $value) {
$suffix = Folder::isSlashTerm($directory->path) ? $value : DS . $value;
$sourcePath = $directory->path . $suffix;
$index = &$importedPaths[$sourcePath];

if ($index === null && $new) {
$data['to_import'][] = $sourcePath;
} elseif (filemtime($sourcePath) > strtotime($importedUpdates[$index]) && $outdated) {
$data['to_update'][] = $index;
$data['imported'][] = $sourcePath;
} else {
$data['imported'][] = $sourcePath;
}

$countToImport = count($data['to_import']);
$countToUpdate = count($data['to_update']);
if ($batch && ($countToImport == $batch || $countToUpdate == $batch)) {
break 3;
} else {
continue;
}
}
}
}

if ($orphans) {
$data['to_remove'] = [];
foreach ($importedPaths as $path => $id) {
if (
!isset(array_flip($data['to_import'])[$path]) &&
!isset(array_flip($data['imported'])[$path])
) {
$data['to_remove'][] = $id;
}
}
}

return $data;
}
}
10 changes: 5 additions & 5 deletions app/Controller/SongsController.php
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ public function beforeFilter() {
*/
public function import() {
App::uses('Folder', 'Utility');
App::uses('SongManager', 'SongManager');
App::uses('AudioFileManager', 'AudioFileManager');

$this->loadModel('Setting');
$this->Setting->contain('Rootpath');
Expand Down Expand Up @@ -124,8 +124,8 @@ public function import() {
break;
}

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

$this->Song->create();
if (!$this->Song->save($parse_result['data'])) {
Expand All @@ -147,8 +147,8 @@ public function import() {
break;
}

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

// Get the song id and enrich the array
$result = $this->Song->find('first', array(
Expand Down
Loading

0 comments on commit d6ca7d3

Please sign in to comment.