├── app
├── Lib
│ ├── empty
│ └── Event
│ │ └── UsersEventListener.php
├── tmp
│ ├── logs
│ │ └── empty
│ └── cache
│ │ ├── models
│ │ └── empty
│ │ ├── sessions
│ │ └── empty
│ │ ├── views
│ │ └── empty
│ │ └── persistent
│ │ └── empty
├── Test
│ ├── Fixture
│ │ └── empty
│ └── Case
│ │ ├── View
│ │ └── Helper
│ │ │ └── empty
│ │ ├── Model
│ │ └── Behavior
│ │ │ └── empty
│ │ └── Controller
│ │ └── Component
│ │ └── empty
├── webroot
│ ├── files
│ │ └── empty
│ ├── favicon.ico
│ ├── img
│ │ ├── no-cover.png
│ │ ├── icon-search.png
│ │ ├── btn_donate_SM.gif
│ │ └── flattr-badge-large.png
│ ├── fonts
│ │ ├── OpenSans-Bold.woff
│ │ ├── OpenSans-Regular.woff
│ │ ├── glyphicons-halflings-regular.eot
│ │ ├── glyphicons-halflings-regular.ttf
│ │ ├── glyphicons-halflings-regular.woff
│ │ └── glyphicons-halflings-regular.woff2
│ ├── .htaccess
│ ├── css
│ │ ├── slider.css
│ │ ├── notify.css
│ │ ├── pace.css
│ │ └── login.css
│ └── js
│ │ ├── albums.js
│ │ ├── jquery.scroll.js
│ │ ├── settings.js
│ │ ├── lazyload.min.js
│ │ └── jquery.list.js
├── Console
│ ├── Templates
│ │ └── empty
│ ├── Command
│ │ ├── Task
│ │ │ └── empty
│ │ └── AppShell.php
│ ├── cake.bat
│ ├── cake
│ └── cake.php
├── Model
│ ├── Behavior
│ │ └── empty
│ ├── Datasource
│ │ └── empty
│ ├── Song.php
│ ├── Playlist.php
│ ├── PlaylistMembership.php
│ ├── AppModel.php
│ ├── Rootpath.php
│ └── Setting.php
├── View
│ ├── Scaffolds
│ │ └── empty
│ ├── Layouts
│ │ ├── xml
│ │ │ └── default.ctp
│ │ ├── js
│ │ │ └── default.ctp
│ │ ├── rss
│ │ │ └── default.ctp
│ │ ├── Emails
│ │ │ ├── text
│ │ │ │ └── default.ctp
│ │ │ └── html
│ │ │ │ └── default.ctp
│ │ ├── installer.ctp
│ │ ├── ajax.ctp
│ │ ├── login.ctp
│ │ ├── flash.ctp
│ │ └── error.ctp
│ ├── Elements
│ │ ├── redirect.ctp
│ │ ├── Flash
│ │ │ ├── info.ctp
│ │ │ ├── error.ctp
│ │ │ └── success.ctp
│ │ ├── pagination.ctp
│ │ ├── add_menu.ctp
│ │ ├── default_navbar.ctp
│ │ └── admin_navbar.ctp
│ ├── Songs
│ │ ├── artists.ctp
│ │ ├── search.ctp
│ │ └── index.ctp
│ ├── Helper
│ │ ├── FileSizeHelper.php
│ │ ├── AjaxHtmlHelper.php
│ │ ├── AppHelper.php
│ │ ├── ImageHelper.php
│ │ └── BootstrapFormHelper.php
│ ├── Emails
│ │ ├── html
│ │ │ ├── user_add.ctp
│ │ │ ├── default.ctp
│ │ │ └── send_token.ctp
│ │ └── text
│ │ │ └── default.ctp
│ ├── PlaylistMemberships
│ │ └── add.ctp
│ ├── Errors
│ │ ├── error500.ctp
│ │ └── error400.ctp
│ ├── Users
│ │ ├── reset_password.ctp
│ │ └── login.ctp
│ └── Installers
│ │ └── docker.ctp
├── Locale
│ └── eng
│ │ └── LC_MESSAGES
│ │ └── empty
├── Plugin
│ └── DebugKit
│ │ ├── VERSION.txt
│ │ ├── webroot
│ │ └── img
│ │ │ └── cake.icon.png
│ │ ├── .gitignore
│ │ ├── View
│ │ ├── ToolbarAccess
│ │ │ ├── sql_explain.ctp
│ │ │ └── history_state.ctp
│ │ ├── Elements
│ │ │ ├── session_panel.ctp
│ │ │ ├── variables_panel.ctp
│ │ │ ├── include_panel.ctp
│ │ │ ├── history_panel.ctp
│ │ │ ├── log_panel.ctp
│ │ │ ├── request_panel.ctp
│ │ │ ├── sql_log_panel.ctp
│ │ │ ├── debug_toolbar.ctp
│ │ │ └── environment_panel.ctp
│ │ └── Helper
│ │ │ ├── SimpleGraphHelper.php
│ │ │ ├── DebugTimerHelper.php
│ │ │ └── FirePhpToolbarHelper.php
│ │ ├── Test
│ │ ├── test_app
│ │ │ ├── View
│ │ │ │ └── DebugKitTest
│ │ │ │ │ └── request_action_render.ctp
│ │ │ ├── Plugin
│ │ │ │ └── DebugkitTestPlugin
│ │ │ │ │ └── Lib
│ │ │ │ │ └── Panel
│ │ │ │ │ └── PluginTestPanel.php
│ │ │ ├── Lib
│ │ │ │ └── Panel
│ │ │ │ │ └── TestPanel.php
│ │ │ └── Controller
│ │ │ │ └── DebugKitTestController.php
│ │ └── Case
│ │ │ ├── AllTestsTest.php
│ │ │ ├── AllDebugKitTest.php
│ │ │ ├── AllDebugKitViewTest.php
│ │ │ ├── AllDebugKitWithoutViewTest.php
│ │ │ ├── Lib
│ │ │ ├── Panel
│ │ │ │ ├── SqlLogPanelTest.php
│ │ │ │ └── LogPanelTest.php
│ │ │ ├── DebugMemoryTest.php
│ │ │ └── DebugKitDebuggerTest.php
│ │ │ ├── TestFireCake.php
│ │ │ ├── Model
│ │ │ ├── ToolbarAccessTest.php
│ │ │ └── Behavior
│ │ │ │ └── TimedBehaviorTest.php
│ │ │ └── DebugkitGroupTestCase.php
│ │ ├── Model
│ │ ├── DebugKitAppModel.php
│ │ ├── ToolbarAccess.php
│ │ └── Behavior
│ │ │ └── TimedBehavior.php
│ │ ├── Controller
│ │ └── DebugKitAppController.php
│ │ ├── Lib
│ │ ├── Panel
│ │ │ ├── SessionPanel.php
│ │ │ ├── VariablesPanel.php
│ │ │ ├── TimerPanel.php
│ │ │ ├── RequestPanel.php
│ │ │ ├── LogPanel.php
│ │ │ ├── SqlLogPanel.php
│ │ │ ├── EnvironmentPanel.php
│ │ │ └── HistoryPanel.php
│ │ ├── Log
│ │ │ └── Engine
│ │ │ │ └── DebugKitLog.php
│ │ ├── DebugPanel.php
│ │ └── DebugMemory.php
│ │ ├── composer.json
│ │ ├── .travis.yml
│ │ └── Console
│ │ └── Command
│ │ └── WhitespaceShell.php
├── .htaccess
├── Config
│ ├── ciphers.php.default
│ ├── Schema
│ │ ├── sessions.sql
│ │ ├── i18n.sql
│ │ ├── db_acl.sql
│ │ ├── sessions.php
│ │ └── i18n.php
│ ├── acl.ini.php
│ ├── routes.php
│ ├── email.php.default
│ └── database.php.default
├── index.php
└── Controller
│ ├── ApiController.php
│ ├── Component
│ ├── UrlComponent.php
│ ├── DateComponent.php
│ └── SortComponent.php
│ └── ImgController.php
├── docs
├── downloads
│ └── empty
├── img
│ └── install.png
├── fonts
│ ├── glyphicons-halflings-regular.eot
│ ├── glyphicons-halflings-regular.ttf
│ ├── glyphicons-halflings-regular.woff
│ └── glyphicons-halflings-regular.woff2
├── about
│ └── license.md
├── css
│ └── style.css
├── user-guides
│ ├── apache-virtual-host.md
│ ├── how-to-upgrade.md
│ ├── cli-tool.md
│ ├── settings.md
│ └── nginx-server-block.md
├── README.md
└── index.md
├── .htaccess
├── .editorconfig
├── composer.json
├── .gitattributes
├── .gitignore
├── mkdocs.yml
├── index.php
├── CONTRIBUTING.md
└── README.md
/app/Lib/empty:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/app/tmp/logs/empty:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/app/Test/Fixture/empty:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/app/webroot/files/empty:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/docs/downloads/empty:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/app/Console/Templates/empty:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/app/Model/Behavior/empty:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/app/Model/Datasource/empty:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/app/View/Scaffolds/empty:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/app/tmp/cache/models/empty:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/app/tmp/cache/sessions/empty:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/app/tmp/cache/views/empty:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/app/Console/Command/Task/empty:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/app/Locale/eng/LC_MESSAGES/empty:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/app/Test/Case/View/Helper/empty:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/app/tmp/cache/persistent/empty:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/app/Test/Case/Model/Behavior/empty:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/app/Plugin/DebugKit/VERSION.txt:
--------------------------------------------------------------------------------
1 | 2.2.3
2 |
--------------------------------------------------------------------------------
/app/Test/Case/Controller/Component/empty:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/app/View/Layouts/xml/default.ctp:
--------------------------------------------------------------------------------
1 | fetch('content'); ?>
2 |
--------------------------------------------------------------------------------
/docs/img/install.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Sonerezh/sonerezh/HEAD/docs/img/install.png
--------------------------------------------------------------------------------
/app/webroot/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Sonerezh/sonerezh/HEAD/app/webroot/favicon.ico
--------------------------------------------------------------------------------
/app/webroot/img/no-cover.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Sonerezh/sonerezh/HEAD/app/webroot/img/no-cover.png
--------------------------------------------------------------------------------
/app/webroot/img/icon-search.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Sonerezh/sonerezh/HEAD/app/webroot/img/icon-search.png
--------------------------------------------------------------------------------
/app/webroot/img/btn_donate_SM.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Sonerezh/sonerezh/HEAD/app/webroot/img/btn_donate_SM.gif
--------------------------------------------------------------------------------
/app/webroot/fonts/OpenSans-Bold.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Sonerezh/sonerezh/HEAD/app/webroot/fonts/OpenSans-Bold.woff
--------------------------------------------------------------------------------
/app/webroot/fonts/OpenSans-Regular.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Sonerezh/sonerezh/HEAD/app/webroot/fonts/OpenSans-Regular.woff
--------------------------------------------------------------------------------
/app/webroot/img/flattr-badge-large.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Sonerezh/sonerezh/HEAD/app/webroot/img/flattr-badge-large.png
--------------------------------------------------------------------------------
/app/Plugin/DebugKit/webroot/img/cake.icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Sonerezh/sonerezh/HEAD/app/Plugin/DebugKit/webroot/img/cake.icon.png
--------------------------------------------------------------------------------
/docs/fonts/glyphicons-halflings-regular.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Sonerezh/sonerezh/HEAD/docs/fonts/glyphicons-halflings-regular.eot
--------------------------------------------------------------------------------
/docs/fonts/glyphicons-halflings-regular.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Sonerezh/sonerezh/HEAD/docs/fonts/glyphicons-halflings-regular.ttf
--------------------------------------------------------------------------------
/docs/fonts/glyphicons-halflings-regular.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Sonerezh/sonerezh/HEAD/docs/fonts/glyphicons-halflings-regular.woff
--------------------------------------------------------------------------------
/docs/fonts/glyphicons-halflings-regular.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Sonerezh/sonerezh/HEAD/docs/fonts/glyphicons-halflings-regular.woff2
--------------------------------------------------------------------------------
/app/View/Layouts/js/default.ctp:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/app/webroot/fonts/glyphicons-halflings-regular.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Sonerezh/sonerezh/HEAD/app/webroot/fonts/glyphicons-halflings-regular.eot
--------------------------------------------------------------------------------
/app/webroot/fonts/glyphicons-halflings-regular.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Sonerezh/sonerezh/HEAD/app/webroot/fonts/glyphicons-halflings-regular.ttf
--------------------------------------------------------------------------------
/app/webroot/fonts/glyphicons-halflings-regular.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Sonerezh/sonerezh/HEAD/app/webroot/fonts/glyphicons-halflings-regular.woff
--------------------------------------------------------------------------------
/app/webroot/fonts/glyphicons-halflings-regular.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Sonerezh/sonerezh/HEAD/app/webroot/fonts/glyphicons-halflings-regular.woff2
--------------------------------------------------------------------------------
/.htaccess:
--------------------------------------------------------------------------------
1 |
2 | RewriteEngine on
3 | RewriteRule ^$ app/webroot/ [L]
4 | RewriteRule (.*) app/webroot/$1 [L]
5 |
--------------------------------------------------------------------------------
/app/.htaccess:
--------------------------------------------------------------------------------
1 |
2 | RewriteEngine on
3 | RewriteRule ^$ webroot/ [L]
4 | RewriteRule (.*) webroot/$1 [L]
5 |
--------------------------------------------------------------------------------
/app/View/Elements/redirect.ctp:
--------------------------------------------------------------------------------
1 | start('script'); ?>
2 |
5 | end(); ?>
--------------------------------------------------------------------------------
/app/View/Elements/Flash/info.ctp:
--------------------------------------------------------------------------------
1 |
2 | element('artists_view'); ?>
3 | element('add_to_playlist'); ?>
4 | element('pagination'); ?>
5 |
--------------------------------------------------------------------------------
/app/Model/Song.php:
--------------------------------------------------------------------------------
1 | Rss->document(
10 | $this->Rss->channel(
11 | array(), $channel, $this->fetch('content')
12 | )
13 | );
14 | ?>
15 |
--------------------------------------------------------------------------------
/app/Plugin/DebugKit/View/ToolbarAccess/sql_explain.ctp:
--------------------------------------------------------------------------------
1 | ',
43 | 'class' => false,
44 | 'legend' => false
45 | );
46 | $options = array_merge($defaultOptions, $options);
47 | }
48 | return parent::input($fieldName, $options);
49 | }
50 |
51 |
52 | protected function _confirm($message, $okCode, $cancelCode = '', $options = array()) {
53 | $ok = explode('.', $okCode);
54 | $okCode = "$('#".$ok[1]."').submit();";
55 | return parent::_confirm($message, $okCode, $cancelCode, $options);
56 | }
57 |
58 | }
59 |
--------------------------------------------------------------------------------
/app/Plugin/DebugKit/View/Elements/sql_log_panel.ctp:
--------------------------------------------------------------------------------
1 | Toolbar->readCache('sql_log', $this->request->params['pass'][0]);
22 | }
23 | ?>
24 |
25 |
26 | $explain): ?>
27 |
28 |
29 | Toolbar->getQueryLogs($dbName, array(
32 | 'explain' => $explain, 'threshold' => $content['threshold']
33 | ));
34 | else:
35 | $queryLog = $content[$dbName];
36 | endif;
37 | echo '
';
38 | echo __d(
39 | 'debug_kit',
40 | 'Total Time: %s ms Total Queries: %s queries',
41 | $queryLog['time'],
42 | $queryLog['count']
43 | );
44 | echo ' ';
45 | echo $this->Toolbar->table($queryLog['queries'], $headers, array('title' => 'SQL Log ' . $dbName));
46 | ?>
47 |
48 |
52 |
53 |
54 | Toolbar->message('Warning', __d('debug_kit', 'No active database connections'));
56 | endif;
57 |
--------------------------------------------------------------------------------
/docs/user-guides/cli-tool.md:
--------------------------------------------------------------------------------
1 | # Command-line tool
2 |
3 | A simple tool available for automation.
4 |
5 | ---
6 |
7 | Since version 1.1.0, a command-line tool is available to process big music
8 | libraries or add some automation. This tool is built on the [CakePHP Shell] and
9 | can be used as below.
10 |
11 | ## Import songs with the CLI
12 |
13 | The CLI can be used to import a single audio file:
14 |
15 | ```text
16 | sonerezh/app $ Console/cake sonerezh import /home/user/Music/file.mp3
17 | Welcome to CakePHP v2.8.1 Console
18 | ---------------------------------------------------------------
19 | App : app
20 | Path: /var/www/sonerezh/app/
21 | ---------------------------------------------------------------
22 | [INFO] You asked to import /home/user/Music/file.mp3. Continue? (yes/no)
23 | [yes] >
24 | [INFO] Run import: [100%] [#############################################]
25 | ```
26 |
27 | It can also scan a directory:
28 |
29 | ```text
30 | sonerezh/app $ Console/cake sonerezh import /home/user/Music/an-album
31 | Welcome to CakePHP v2.8.1 Console
32 | ---------------------------------------------------------------
33 | App : app
34 | Path: /var/www/sonerezh/app/
35 | ---------------------------------------------------------------
36 | [INFO] Scan /home/user/Music/an-album...
37 | [INFO] Found 13 audio files (0 already in the database). Continue? (yes/no)
38 | [yes] >
39 | [INFO] Run import: [100%] [#############################################]
40 | ```
41 |
42 | Or you can scan a complete folder tree using the ``--recursive`` option:
43 |
44 | ```text
45 | sonerezh/app $ Console/cake sonerezh import -r /home/user/Music
46 | Welcome to CakePHP v2.8.1 Console
47 | ---------------------------------------------------------------
48 | App : app
49 | Path: /var/www/sonerezh/app/
50 | ---------------------------------------------------------------
51 | [INFO] Scan /home/user/Music...
52 | [INFO] Found 614 audio files (13 already in the database). Continue? (yes/no)
53 | [yes] >
54 | [INFO] Run import: [100%] [#############################################]
55 | ```
56 |
57 | The imported files are immediately available on the web interface.
58 |
59 | [CakePHP Shell]: http://book.cakephp.org/2.0/en/console-and-shells.html
--------------------------------------------------------------------------------
/app/View/Layouts/Emails/html/default.ctp:
--------------------------------------------------------------------------------
1 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 | fetch('content'); ?>
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
--------------------------------------------------------------------------------
/app/Plugin/DebugKit/Lib/DebugPanel.php:
--------------------------------------------------------------------------------
1 | firecake = FireCake::getInstance('TestFireCake');
38 | TestFireCake::reset();
39 | }
40 |
41 | /**
42 | * tearDown method
43 | *
44 | * @return void
45 | */
46 | public function tearDown() {
47 | parent::tearDown();
48 | Configure::write('log', true);
49 | DebugKitDebugger::clearTimers();
50 | TestFireCake::reset();
51 | }
52 |
53 | /**
54 | * test output switch to firePHP
55 | *
56 | * @return void
57 | */
58 | public function testOutput() {
59 | Debugger::getInstance('DebugKitDebugger');
60 | Debugger::addFormat('fb', array('callback' => 'DebugKitDebugger::fireError'));
61 | Debugger::outputAs('fb');
62 |
63 | set_error_handler('ErrorHandler::handleError');
64 | $foo .= '';
65 | restore_error_handler();
66 |
67 | $result = $this->firecake->sentHeaders;
68 |
69 | $this->assertRegExp('/GROUP_START/', $result['X-Wf-1-1-1-1']);
70 | $this->assertRegExp('/ERROR/', $result['X-Wf-1-1-1-2']);
71 | $this->assertRegExp('/GROUP_END/', $result['X-Wf-1-1-1-5']);
72 |
73 | Debugger::getInstance('Debugger');
74 | Debugger::outputAs('html');
75 | }
76 | }
77 |
--------------------------------------------------------------------------------
/app/Config/acl.ini.php:
--------------------------------------------------------------------------------
1 | ;
2 | ;/**
3 | ; * ACL Configuration
4 | ; *
5 | ; * CakePHP(tm) : Rapid Development Framework (http://cakephp.org)
6 | ; * Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
7 | ; *
8 | ; * Licensed under The MIT License
9 | ; * Redistributions of files must retain the above copyright notice.
10 | ; *
11 | ; * @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org)
12 | ; * @link http://cakephp.org CakePHP(tm) Project
13 | ; * @package app.Config
14 | ; * @since CakePHP(tm) v 0.10.0.1076
15 | ; * @license http://www.opensource.org/licenses/mit-license.php MIT License
16 | ; */
17 |
18 | ; acl.ini.php - Cake ACL Configuration
19 | ; ---------------------------------------------------------------------
20 | ; Use this file to specify user permissions.
21 | ; aco = access control object (something in your application)
22 | ; aro = access request object (something requesting access)
23 | ;
24 | ; User records are added as follows:
25 | ;
26 | ; [uid]
27 | ; groups = group1, group2, group3
28 | ; allow = aco1, aco2, aco3
29 | ; deny = aco4, aco5, aco6
30 | ;
31 | ; Group records are added in a similar manner:
32 | ;
33 | ; [gid]
34 | ; allow = aco1, aco2, aco3
35 | ; deny = aco4, aco5, aco6
36 | ;
37 | ; The allow, deny, and groups sections are all optional.
38 | ; NOTE: groups names *cannot* ever be the same as usernames!
39 | ;
40 | ; ACL permissions are checked in the following order:
41 | ; 1. Check for user denies (and DENY if specified)
42 | ; 2. Check for user allows (and ALLOW if specified)
43 | ; 3. Gather user's groups
44 | ; 4. Check group denies (and DENY if specified)
45 | ; 5. Check group allows (and ALLOW if specified)
46 | ; 6. If no aro, aco, or group information is found, DENY
47 | ;
48 | ; ---------------------------------------------------------------------
49 |
50 | ;-------------------------------------
51 | ;Users
52 | ;-------------------------------------
53 |
54 | [username-goes-here]
55 | groups = group1, group2
56 | deny = aco1, aco2
57 | allow = aco3, aco4
58 |
59 | ;-------------------------------------
60 | ;Groups
61 | ;-------------------------------------
62 |
63 | [groupname-goes-here]
64 | deny = aco5, aco6
65 | allow = aco7, aco8
66 |
--------------------------------------------------------------------------------
/app/Plugin/DebugKit/Test/Case/DebugkitGroupTestCase.php:
--------------------------------------------------------------------------------
1 | valid()) {
60 |
61 | if (!$it->isDot()) {
62 | $file = $it->key();
63 |
64 | if (
65 | preg_match('|Test\.php$|', $file) &&
66 | $file !== __FILE__ &&
67 | !preg_match('|^All.+?\.php$|', basename($file)) &&
68 | ($excludes === null || !in_array($file, $excludes))
69 | ) {
70 | $files[] = $file;
71 | }
72 | }
73 |
74 | $it->next();
75 | }
76 |
77 | return $files;
78 | }
79 | }
80 |
--------------------------------------------------------------------------------
/app/Plugin/DebugKit/View/Elements/debug_toolbar.ctp:
--------------------------------------------------------------------------------
1 |
21 |
60 |
--------------------------------------------------------------------------------
/app/Plugin/DebugKit/Test/Case/Model/Behavior/TimedBehaviorTest.php:
--------------------------------------------------------------------------------
1 | Article = ClassRegistry::init('Article');
43 | $this->Article->Behaviors->attach('DebugKit.Timed');
44 | }
45 |
46 | /**
47 | * End a test
48 | *
49 | * @return void
50 | */
51 | public function tearDown() {
52 | parent::tearDown();
53 | unset($this->Article);
54 | ClassRegistry::flush();
55 | DebugKitDebugger::clearTimers();
56 | }
57 |
58 | /**
59 | * Test find timers
60 | *
61 | * @return void
62 | */
63 | public function testFindTimers() {
64 | $timers = DebugKitDebugger::getTimers(false);
65 | $this->assertEquals(count($timers), 1);
66 |
67 | $this->Article->find('all');
68 | $result = DebugKitDebugger::getTimers(false);
69 | $this->assertEquals(count($result), 2);
70 |
71 | $this->Article->find('all');
72 | $result = DebugKitDebugger::getTimers(false);
73 | $this->assertEquals(count($result), 3);
74 | }
75 |
76 | /**
77 | * Test save timers
78 | *
79 | * @return void
80 | */
81 | public function testSaveTimers() {
82 | $timers = DebugKitDebugger::getTimers(false);
83 | $this->assertEquals(count($timers), 1);
84 |
85 | $this->Article->save(array('user_id' => 1, 'title' => 'test', 'body' => 'test'));
86 | $result = DebugKitDebugger::getTimers(false);
87 | $this->assertEquals(count($result), 2);
88 | }
89 | }
90 |
--------------------------------------------------------------------------------
/app/webroot/js/settings.js:
--------------------------------------------------------------------------------
1 | $(function(){
2 | var mp3Quality = {min: 56, max: 320, steps:[128, 192, 256]};
3 | var oggQuality = {min: 0, max: 10, steps:[1, 2, 3, 4, 5, 6, 7, 8, 9]};
4 | var mp3Val = 256;
5 | var oggVal = 8;
6 | var init = true;
7 |
8 | $('#quality-slider').slider({change: function(val) {
9 | $('#SettingQuality').val(val);
10 | updateSlider();
11 | }});
12 |
13 | $('[name="data[Setting][convert_to]"]').change(function(){
14 | var $checked = $('[name="data[Setting][convert_to]"]:checked');
15 | if($checked.val() == "mp3") {
16 | $('#quality-slider').slider(mp3Quality);
17 | if(!init) {
18 | $('#SettingQuality').val(mp3Val);
19 | }
20 | }else {
21 | $('#quality-slider').slider(oggQuality);
22 | if(!init) {
23 | $('#SettingQuality').val(oggVal);
24 | }
25 | }
26 | init = false;
27 | $('#quality-slider').slider('value', $('#SettingQuality').val());
28 | updateSlider();
29 | }).change();
30 |
31 | function updateSlider() {
32 | var val = $('#SettingQuality').val();
33 | if($('[name="data[Setting][convert_to]"]:checked').val() == "mp3") {
34 | mp3Val = val;
35 | val += 'kb/s';
36 | }else {
37 | oggVal = val;
38 | }
39 | $('.quality div:last').text(val);
40 | }
41 |
42 | $('#SettingIndexForm').on('click', '.remove-dir', function(){
43 | $(this).parents('.rootpath').remove();
44 | updateRootpathIndex();
45 | });
46 |
47 | $('#add-root-path-field').click(function(){
48 | var $field = $(this).parents('.rootpath').clone();
49 | $field.find('input[type=hidden]').remove();
50 | $field.find('input').val("");
51 | $field.removeAttr('id').find('button').removeAttr('id').toggleClass('btn-primary btn-danger remove-dir').find('i').toggleClass('glyphicon-plus glyphicon-minus');
52 | $(this).parents('.rootpath').after($field);
53 | updateRootpathIndex();
54 | });
55 |
56 | function updateRootpathIndex(){
57 | $('.rootpath').each(function(i, e){
58 | $(e).find('input').each(function(index, element){
59 | var name = $(element).attr('name').replace(/\]\[([0-9]+)\]\[/, "]["+i+"][");
60 | $(element).attr('name', name);
61 | });
62 | });
63 | }
64 |
65 | });
--------------------------------------------------------------------------------
/app/Plugin/DebugKit/View/Helper/SimpleGraphHelper.php:
--------------------------------------------------------------------------------
1 | (int) Maximum value in the graphs
40 | * - width => (int)
41 | * - valueType => string (value, percentage)
42 | * - style => array
43 | *
44 | * @var array
45 | */
46 | protected $_defaultSettings = array(
47 | 'max' => 100,
48 | 'width' => 350,
49 | 'valueType' => 'value',
50 | );
51 |
52 | /**
53 | * bar method
54 | *
55 | * @param $value Value to be graphed
56 | * @param $offset how much indentation
57 | * @param array|\Graph $options Graph options
58 | * @return string Html graph
59 | */
60 | public function bar($value, $offset, $options = array()) {
61 | $settings = array_merge($this->_defaultSettings, $options);
62 | extract($settings);
63 |
64 | $graphValue = ($value / $max) * $width;
65 | $graphValue = max(round($graphValue), 1);
66 |
67 | if ($valueType === 'percentage') {
68 | $graphOffset = 0;
69 | } else {
70 | $graphOffset = ($offset / $max) * $width;
71 | $graphOffset = round($graphOffset);
72 | }
73 | return $this->Html->div(
74 | 'debug-kit-graph-bar',
75 | $this->Html->div(
76 | 'debug-kit-graph-bar-value',
77 | ' ',
78 | array(
79 | 'style' => "margin-left: {$graphOffset}px; width: {$graphValue}px",
80 | 'title' => __d('debug_kit', "Starting %sms into the request, taking %sms", $offset, $value),
81 | )
82 | ),
83 | array('style' => "width: {$width}px;"),
84 | false
85 | );
86 | }
87 |
88 | }
89 |
--------------------------------------------------------------------------------
/app/View/Elements/admin_navbar.ctp:
--------------------------------------------------------------------------------
1 |
2 | Html->link(__('Artists'), array('controller' => 'songs', 'action' => 'artists')); ?>
3 | Html->link(__('Albums'), array('controller' => 'songs', 'action' => 'albums')); ?>
4 | Html->link(__('Playlists'), array('controller' => 'playlists', 'action' => 'index')); ?>
5 |
6 |
11 |
12 | Html->link(' ', array('controller' => 'songs', 'action' => 'search'), array('data-toggle' => 'tooltip', 'data-placement' => 'bottom', 'title' => __('Search'), 'class' => 'nav-tooltips', 'escape' => false)); ?>
13 | Html->link(' ', array('controller' => 'songs', 'action' => 'import'), array('data-toggle' => 'tooltip', 'data-placement' => 'bottom', 'title' => __('Database update'), 'class' => 'nav-tooltips', 'escape' => false)); ?>
14 | Html->link(' ', array('controller' => 'settings', 'action' => 'index'), array('data-toggle' => 'tooltip', 'data-placement' => 'bottom', 'title' => __('Settings'), 'class' => 'nav-tooltips', 'escape' => false)); ?>
15 | Html->link(' ', array('controller' => 'users', 'action' => 'index'), array('data-toggle' => 'tooltip', 'data-placement' => 'bottom', 'title' => __('Users'), 'class' => 'nav-tooltips', 'escape' => false)); ?>
16 | Html->link(' ', array('controller' => 'users', 'action' => 'logout'), array('data-toggle' => 'tooltip', 'data-placement' => 'bottom', 'title' => __('Logout'), 'class' => 'nav-tooltips no-ajax', 'escape' => false)); ?>
17 |
18 | Html->image($this->Image->avatar(AuthComponent::user(), 30), array('alt' => 'Avatar image', 'class' => 'img-responsive nav-tooltips', 'style' => 'padding: 10px 15px;', 'data-toggle' => 'tooltip', 'data-placement' => 'bottom', 'title' => __('Hi :)'))); ?>
19 |
20 |
--------------------------------------------------------------------------------
/app/Plugin/DebugKit/View/Helper/DebugTimerHelper.php:
--------------------------------------------------------------------------------
1 | _renderComplete) {
56 | return;
57 | }
58 | DebugTimer::start(
59 | 'render_' . basename($viewFile),
60 | __d('debug_kit', 'Rendering %s',
61 | Debugger::trimPath($viewFile))
62 | );
63 | }
64 |
65 | /**
66 | * Stops the timer point before rendering a file.
67 | *
68 | * @param string $viewFile The view being rendered
69 | * @param string $content The contents of the view.
70 | */
71 | public function afterRenderFile($viewFile, $content) {
72 | if ($this->_renderComplete) {
73 | return;
74 | }
75 | DebugTimer::stop('render_' . basename($viewFile));
76 | }
77 |
78 | /**
79 | * Stop timers for rendering.
80 | *
81 | * @param string $layoutFile
82 | */
83 | public function afterLayout($layoutFile) {
84 | DebugTimer::stop('viewRender');
85 | DebugTimer::stop('controllerRender');
86 | DebugMemory::record(__d('debug_kit', 'View render complete'));
87 | $this->_renderComplete = true;
88 | }
89 |
90 | }
91 |
--------------------------------------------------------------------------------
/app/Plugin/DebugKit/.travis.yml:
--------------------------------------------------------------------------------
1 | language: php
2 |
3 | php:
4 | - 5.3
5 | - 5.4
6 | - 5.5
7 |
8 | env:
9 | - CAKE_VERSION=2.2.7 DB=mysql
10 | - CAKE_VERSION=2.2.7 DB=pgsql
11 | - CAKE_VERSION=master DB=mysql
12 | - CAKE_VERSION=master DB=pgsql
13 | - CAKE_VERSION=2.4.1 DB=mysql
14 | - CAKE_VERSION=2.4.1 DB=pgsql
15 |
16 | before_script:
17 | - sh -c "if [ '$DB' = 'mysql' ]; then mysql -e 'CREATE DATABASE cakephp_test;'; fi"
18 | - sh -c "if [ '$DB' = 'pgsql' ]; then psql -c 'CREATE DATABASE cakephp_test;' -U postgres; fi"
19 | - git clone git://github.com/cakephp/cakephp ../cakephp && cd ../cakephp && git checkout $CAKE_VERSION
20 | - cp -R ../debug_kit plugins/DebugKit
21 | - chmod -R 777 ../cakephp/app/tmp
22 | - set +H
23 | - echo " array(
27 | 'datasource' => 'Database/Mysql',
28 | 'host' => '0.0.0.0',
29 | 'login' => 'travis'
30 | ),
31 | 'pgsql' => array(
32 | 'datasource' => 'Database/Postgres',
33 | 'host' => '127.0.0.1',
34 | 'login' => 'postgres',
35 | 'database' => 'cakephp_test',
36 | 'schema' => array(
37 | 'default' => 'public',
38 | 'test' => 'public'
39 | )
40 | )
41 | );
42 | public \$default = array(
43 | 'persistent' => false,
44 | 'host' => '',
45 | 'login' => '',
46 | 'password' => '',
47 | 'database' => 'cakephp_test',
48 | 'prefix' => ''
49 | );
50 | public \$test = array(
51 | 'persistent' => false,
52 | 'host' => '',
53 | 'login' => '',
54 | 'password' => '',
55 | 'database' => 'cakephp_test',
56 | 'prefix' => ''
57 | );
58 | public function __construct() {
59 | \$db = 'mysql';
60 | if (!empty(\$_SERVER['DB'])) {
61 | \$db = \$_SERVER['DB'];
62 | }
63 | foreach (array('default', 'test') as \$source) {
64 | \$config = array_merge(\$this->{\$source}, \$this->identities[\$db]);
65 | if (is_array(\$config['database'])) {
66 | \$config['database'] = \$config['database'][\$source];
67 | }
68 | if (!empty(\$config['schema']) && is_array(\$config['schema'])) {
69 | \$config['schema'] = \$config['schema'][\$source];
70 | }
71 | \$this->{\$source} = \$config;
72 | }
73 | }
74 | }" > ../cakephp/app/Config/database.php
75 |
76 | script:
77 | - ./lib/Cake/Console/cake test DebugKit AllDebugKit --stderr
78 |
79 | notifications:
80 | email: false
81 |
--------------------------------------------------------------------------------
/docs/user-guides/settings.md:
--------------------------------------------------------------------------------
1 | # Settings Reference
2 |
3 | Guide to all available configuration settings.
4 |
5 | ---
6 |
7 | ## About the configuration
8 |
9 | The settings can be configured on the ``/settings`` page. You will find some
10 | statistics related to the current installation and buttons used to manage the
11 | database and the caches.
12 |
13 | ### Music root directory
14 |
15 | Here you can specify the absolute path of the folder in which Sonerezh must look
16 | for your music.
17 |
18 | !!! Note
19 |
20 | Make sure Sonerezh can read this folder recursively.
21 |
22 | !!! Warning
23 |
24 | We strongly recommend to **NOT** store any audio file into the Sonerezh
25 | application directory.
26 |
27 | ### Email notifications
28 |
29 | Sonerezh can send email to new users, or allow them to retrieve a forgotten
30 | password. Make sure PHP can send emails before enable this option.
31 |
32 | Just like the database configuration, email configuration can be centralized in
33 | a class called ``EmailConfig``, in ``app/Config/email.php``. The
34 | ``app/Config/email.php.default`` has an example for this file.
35 |
36 | You can follow the [official CakePHP documentation] to configure the different
37 | transport methods to send email. The following configuration should work in most
38 | cases (if you already have a MTA available).
39 |
40 | ```php
41 | class EmailConfig {
42 | public $default = array(
43 | 'transport' => 'Mail',
44 | 'from' => 'no-reply@sonerezh.bzh',
45 | 'charset' => 'utf-8',
46 | 'headerCharset' => 'utf-8',
47 | );
48 | }
49 | ```
50 |
51 | In this example, Sonerezh will send email using the PHP function ``mail()``.
52 |
53 | ### Automatic track conversion
54 |
55 | If your library contains tracks which can not be read by your browser, Sonerezh
56 | can convert them to OGG/Vorbis or MP3.
57 |
58 | !!! Note
59 |
60 | Sonerezh requires ``avconv`` or ``ffmpeg`` to convert the tracks.
61 |
62 | ### Database management
63 |
64 | The settings page allows you to make some maintenance operations on Sonerezh,
65 | its database and its caches:
66 |
67 | * Database update: run the import process. Useful if you have recently added new
68 | songs
69 | * Clear the cache : empty the cache (converted tracks and resized covers)
70 | * Reset the database : reset the database. All songs and playlists
71 | **WILL BE LOST**. Don't panic, Sonerezh will never modify or delete any file
72 | on the filesystem
73 |
74 | [official CakePHP documentation]: http://book.cakephp.org/2.0/en/core-utility-libraries/email.html
--------------------------------------------------------------------------------
/app/View/Users/login.ctp:
--------------------------------------------------------------------------------
1 |
2 | Form->create('User'); ?>
3 |
4 | Sonerezh -
5 |
6 | Form->input('email', array('placeholder' => __('Email Address'), 'required')); ?>
7 | Form->input('password', array('placeholder' => __('Password'), 'required')); ?>
8 |
9 | Form->input('rememberme', array('type' => 'checkbox', 'label' => __('Remember me'), 'div' => array('class' => 'checkbox pull-left'))); ?>
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 | Form->submit(__('Sign In'), array('class' => 'btn btn-lg btn-success btn-block')); ?>
18 |
19 |
20 |
21 | Form->end(); ?>
22 |
23 |
24 |
25 |
26 |
27 | Form->create('User', array('url' => array('controller' => 'users', 'action' => 'setResetPasswordToken'))); ?>
28 |
32 |
33 | Form->input('email', array(
35 | 'placeholder' => __('Enter your email'),
36 | 'after' => ''.__('If your account exists, you will receive an email explaining how to change your password.').' ')
37 | );
38 | ?>
39 |
40 |
43 | Form->end(); ?>
44 |
45 |
46 |
--------------------------------------------------------------------------------
/app/Plugin/DebugKit/Lib/Panel/EnvironmentPanel.php:
--------------------------------------------------------------------------------
1 | $phpVer), $_SERVER);
43 | unset($return['php']['argv']);
44 |
45 | // CakePHP Data
46 | $return['cake'] = array(
47 | 'APP' => APP,
48 | 'APP_DIR' => APP_DIR,
49 | 'APPLIBS' => APPLIBS,
50 | 'CACHE' => CACHE,
51 | 'CAKE' => CAKE,
52 | 'CAKE_CORE_INCLUDE_PATH' => CAKE_CORE_INCLUDE_PATH,
53 | 'CORE_PATH' => CORE_PATH,
54 | 'CAKE_VERSION' => Configure::version(),
55 | 'CSS' => CSS,
56 | 'CSS_URL' => CSS_URL,
57 | 'DS' => DS,
58 | 'FULL_BASE_URL' => FULL_BASE_URL,
59 | 'IMAGES' => IMAGES,
60 | 'IMAGES_URL' => IMAGES_URL,
61 | 'JS' => JS,
62 | 'JS_URL' => JS_URL,
63 | 'LOGS' => LOGS,
64 | 'ROOT' => ROOT,
65 | 'TESTS' => TESTS,
66 | 'TMP' => TMP,
67 | 'VENDORS' => VENDORS,
68 | 'WEBROOT_DIR' => WEBROOT_DIR,
69 | 'WWW_ROOT' => WWW_ROOT
70 | );
71 |
72 | $cakeConstants = array_fill_keys(
73 | array(
74 | 'DS', 'ROOT', 'FULL_BASE_URL', 'TIME_START', 'SECOND', 'MINUTE', 'HOUR', 'DAY', 'WEEK', 'MONTH', 'YEAR',
75 | 'LOG_ERROR', 'FULL_BASE_URL'
76 | ), ''
77 | );
78 | $var = get_defined_constants(true);
79 | $return['app'] = array_diff_key($var['user'], $return['cake'], $cakeConstants);
80 |
81 | if (isset($var['hidef'])) {
82 | $return['hidef'] = $var['hidef'];
83 | }
84 |
85 | return $return;
86 | }
87 | }
88 |
--------------------------------------------------------------------------------
/app/Plugin/DebugKit/Lib/Panel/HistoryPanel.php:
--------------------------------------------------------------------------------
1 | history = $settings['history'];
44 | }
45 | }
46 |
47 | /**
48 | * beforeRender callback function
49 | *
50 | * @param Controller $controller
51 | * @return array contents for panel
52 | */
53 | public function beforeRender(Controller $controller) {
54 | $cacheKey = $controller->Toolbar->cacheKey;
55 | $toolbarHistory = Cache::read($cacheKey, 'debug_kit');
56 | $historyStates = array();
57 | if (is_array($toolbarHistory) && !empty($toolbarHistory)) {
58 | $prefix = array();
59 | if (!empty($controller->request->params['prefix'])) {
60 | $prefix[$controller->request->params['prefix']] = false;
61 | }
62 | foreach ($toolbarHistory as $i => $state) {
63 | if (!isset($state['request']['content']['url'])) {
64 | continue;
65 | }
66 | $title = $state['request']['content']['url'];
67 | $query = @$state['request']['content']['query'];
68 | if (isset($query['url'])) {
69 | unset($query['url']);
70 | }
71 | if (!empty($query)) {
72 | $title .= '?' . urldecode(http_build_query($query));
73 | }
74 | $historyStates[] = array(
75 | 'title' => $title,
76 | 'url' => array_merge($prefix, array(
77 | 'plugin' => 'debug_kit',
78 | 'controller' => 'toolbar_access',
79 | 'action' => 'history_state',
80 | $i + 1))
81 | );
82 | }
83 | }
84 | if (count($historyStates) >= $this->history) {
85 | array_pop($historyStates);
86 | }
87 | return $historyStates;
88 | }
89 | }
90 |
--------------------------------------------------------------------------------
/app/Plugin/DebugKit/View/Elements/environment_panel.ctp:
--------------------------------------------------------------------------------
1 |
20 |
21 | $val) {
25 | $cakeRows[] = array(
26 | $key,
27 | $val
28 | );
29 | }
30 | $headers = array('Constant', 'Value');
31 | echo $this->Toolbar->table($cakeRows, $headers, array('title' => 'Application Environment Vars'));
32 | } else {
33 | echo "No application environment available.";
34 | } ?>
35 |
36 |
37 | $val) {
41 | $cakeRows[] = array(
42 | $key,
43 | $val
44 | );
45 | }
46 | $headers = array('Constant', 'Value');
47 | echo $this->Toolbar->table($cakeRows, $headers, array('title' => 'CakePHP Environment Vars'));
48 | } else {
49 | echo "CakePHP environment unavailable.";
50 | } ?>
51 |
52 |
53 | $val) {
59 | $phpRows[] = array(
60 | Inflector::humanize(strtolower($key)),
61 | $val
62 | );
63 | }
64 | echo $this->Toolbar->table($phpRows, $headers, array('title' => 'CakePHP Environment Vars'));
65 | } else {
66 | echo "PHP environment unavailable.";
67 | }
68 |
69 | if (isset($content['hidef'])) {
70 | echo '
' . __d('debug_kit', 'Hidef Environment') . ' ';
71 | if (!empty($content['hidef'])) {
72 | $cakeRows = array();
73 | foreach ($content['hidef'] as $key => $val) {
74 | $cakeRows[] = array(
75 | $key,
76 | $val
77 | );
78 | }
79 | $headers = array('Constant', 'Value');
80 | echo $this->Toolbar->table($cakeRows, $headers, array('title' => 'Hidef Environment Vars'));
81 | } else {
82 | echo "No Hidef environment available.";
83 | }
84 | }
85 |
--------------------------------------------------------------------------------
/app/Model/Setting.php:
--------------------------------------------------------------------------------
1 | array(
10 | 'boolean' => array(
11 | 'rule' => array('boolean'),
12 | 'message' => 'Something went wrong!'
13 | )
14 | ),
15 | 'convert_to' => array(
16 | 'inList' => array(
17 | 'rule' => array('inList', array('mp3', 'ogg')),
18 | 'message' => 'Wrong conversion destination!'
19 | ),
20 | 'convConflicts' => array(
21 | 'rule' => array('convConflicts'),
22 | 'message' => "Wrong conversion destination! Make sure you are not trying to convert MP3 to MP3, or OGG to OGG."
23 | )
24 | ),
25 | 'enable_mail_notification' => array(
26 | 'boolean' => array(
27 | 'rule' => array('boolean'),
28 | 'message' => 'Something went wrong!'
29 | )
30 | )
31 | );
32 |
33 | public function beforeSave($options = array()) {
34 | // On place les fichiers à convertir dans ['convert_from']
35 | $this->data[$this->alias]['convert_from'] = '';
36 | if (isset($this->data[$this->alias]['from_mp3']) && $this->data[$this->alias]['from_mp3']) {
37 | $this->data[$this->alias]['convert_from'] .= 'mp3,';
38 | }
39 | if (isset($this->data[$this->alias]['from_ogg']) && $this->data[$this->alias]['from_ogg']) {
40 | $this->data[$this->alias]['convert_from'] .= 'ogg,';
41 | }
42 | if (isset($this->data[$this->alias]['from_flac']) && $this->data[$this->alias]['from_flac']) {
43 | $this->data[$this->alias]['convert_from'] .= 'flac,';
44 | }
45 | // On force la conversion des fichiers AAC
46 | $this->data[$this->alias]['convert_from'] .= 'aac';
47 | return true;
48 | }
49 |
50 | public function convConflicts($options = array()) {
51 | // Make sure Sonerezh will not try to convert MP3 to MP3 or OGG to OGG
52 | if (isset($this->data[$this->alias]['from_mp3'])) {
53 | if ($this->data[$this->alias]['from_mp3'] && $this->data[$this->alias]['convert_to'] == 'mp3') {
54 | return false;
55 | }
56 | }
57 |
58 | if (isset($this->data[$this->alias]['from_ogg'])) {
59 | if ($this->data[$this->alias]['from_ogg'] && $this->data[$this->alias]['convert_to'] == 'ogg') {
60 | return false;
61 | }
62 | }
63 | return true;
64 | }
65 |
66 | }
--------------------------------------------------------------------------------
/app/Config/routes.php:
--------------------------------------------------------------------------------
1 | 'songs', 'action' => 'index'));
28 |
29 | Router::connect('/install', array('controller' => 'installers', 'action' => 'index'));
30 | Router::connect('/docker-install', array('controller' => 'installers', 'action' => 'docker'));
31 |
32 | Router::connect('/login', array('controller' => 'users', 'action' => 'login'));
33 | Router::connect('/logout', array('controller' => 'users', 'action' => 'logout'));
34 |
35 | Router::connect('/api/*', array('controller' => 'api'));
36 |
37 | Router::connect('/playlists/:action/:id', array('controller' => 'playlists'), array('pass' => array('id')));
38 | Router::connect('/playlists/add', array('controller' => 'playlists', 'action' => 'add'));
39 | Router::connect('/playlists/*', array('controller' => 'playlists', 'action' => 'index'));
40 |
41 | Router::connect('/users', array('controller' => 'users', 'action' => 'index'));
42 |
43 | Router::connect('/settings', array('controller' => 'settings', 'action' => 'index'));
44 |
45 | Router::connect('/img/**', array('controller' => 'img', 'action' => 'index'));
46 |
47 | Router::connect('/:action', array('controller' => 'songs'));
48 |
49 | /**
50 | * Load all plugin routes. See the CakePlugin documentation on
51 | * how to customize the loading of plugin routes.
52 | */
53 | CakePlugin::routes();
54 |
55 | /**
56 | * Load the CakePHP default routes. Only remove this if you do not want to use
57 | * the built-in default routes.
58 | */
59 | require CAKE . 'Config' . DS . 'routes.php';
60 |
--------------------------------------------------------------------------------
/docs/index.md:
--------------------------------------------------------------------------------
1 | # Sonerezh
2 |
3 | A self-hosted, web-based application to stream your music, everywhere.
4 |
5 | ---
6 |
7 | ## Overview
8 |
9 | Sonerezh is a self-hosted, web-based audio streaming application allowing you
10 | to access your music from anywhere, using your favorite web browser.
11 |
12 | **Automatic import**
13 |
14 | Tell Sonerezh where your music is stored and that's all. It will parse and
15 | extract the metadata of each files to built its own database. We currently
16 | support MP3 and MP4, OGG/Vorbis (.ogg and .flac) files.
17 |
18 | **Beautiful Web-UI**
19 |
20 | Browse you favorite music through several beautiful views, sort your collection
21 | by band, album, date, etc.
22 |
23 | **2-clicks installation**
24 |
25 | Sonerezh is easy to install thanks to its automatic deployment tool. No
26 | headaches with configuration files.
27 |
28 | ---
29 |
30 | ## Installation
31 |
32 | Sonerezh is quite easy to install. All you need is:
33 |
34 | - A web server (Apache2, Nginx...)
35 | - PHP, with the following modules enabled: ``php-mysql`` and ``php-gd``
36 | (with ``exif.so``)
37 | - A database (MySQL or MariaDB)
38 | - Optionally ``avconv`` or ``ffmpeg`` if you plan to use the conversion tool
39 |
40 | !!! Note
41 |
42 | This documentation will **NOT** cover the installation of NGINX or PHP. A lot
43 | of tutorials are already available on the web.
44 |
45 | However, configuration samples are available for NGINX or Apache.
46 |
47 | ### Get the latest stable release
48 |
49 | The releases are published on [GitHub], but you should download the latest
50 | stable release from _sonerezh.bzh_.
51 |
52 | ```sh
53 | # Replace tar.gz with zip if needed.
54 | $ wget https://www.sonerezh.bzh/downloads/latest.tar.gz
55 | $ tar -zxf latest.tar.gz
56 | ```
57 |
58 | ### Prepare the database
59 |
60 | The database must be created before you access Sonerezh for the first time.
61 | A simple setup could be:
62 |
63 | ```sql
64 | $ mysql -u root -p
65 | mysql> CREATE DATABASE sonerezh;
66 | mysql> GRANT ALL PRIVILEGES ON sonerezh.* TO 'sonerezh'@'localhost' IDENTIFIED BY '
';
67 | mysql> FLUSH PRIVILEGES;
68 | exit;
69 | ```
70 |
71 | Where ```` is the password used by the MySQL user.
72 |
73 | ---
74 |
75 | ## Getting started
76 |
77 | You may want to allow the web server system account to read this directory.
78 | Usually its ``www-data``.
79 |
80 | ```sh
81 | $ sudo chown -R www-data: sonerezh
82 | ```
83 |
84 | Now you can go to ``http://127.0.0.1/install`` (or whatever configured domain
85 | name) to set the database settings and create the first user.
86 |
87 | 
88 |
89 | If all goes well you should be redirected to the login page.
90 |
91 | [GitHub]: https://github.com/Sonerezh/sonerezh/releases
92 |
--------------------------------------------------------------------------------
/docs/user-guides/nginx-server-block.md:
--------------------------------------------------------------------------------
1 | # NGINX server-block
2 |
3 | This is a minimalist configuration sample for NGINX.
4 |
5 | ```nginx
6 | upstream php-fpm {
7 | server unix:/var/run/php-fpm.sock;
8 | }
9 |
10 | server {
11 | listen 80;
12 | server_name demo.sonerezh.bzh;
13 | root /var/www/sonerezh/app/webroot;
14 |
15 | index index.php;
16 |
17 | location / {
18 | try_files $uri $uri/ /index.php?$args;
19 | expires 14d;
20 | add_header Cache-Control 'public';
21 | }
22 |
23 | # The section below handle the thumbnails cache, on the client (browser)
24 | # side (optional but recommended)
25 | location ~* /([^/]+_[0-9]+x[0-9]+(@[0-9]+x)?\.[a-z]+)$ {
26 | try_files /img/resized/$1 /index.php?$args;
27 | add_header Cache-Control 'public';
28 | expires 14d;
29 | access_log off;
30 | }
31 |
32 | location ~ \.php$ {
33 | try_files $uri =404;
34 | fastcgi_index index.php;
35 | fastcgi_pass php-fpm;
36 | include fastcgi.conf;
37 |
38 | # If fastcgi.conf is not available on your platform you may want to
39 | # uncomment the following line
40 | #fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
41 | }
42 | }
43 | ```
44 |
45 | To run Sonerezh on a subfolder instead of a subdomain, here is an other example.
46 |
47 | ```nginx
48 | upstream php-fpm {
49 | server unix:/var/run/php-fpm.sock;
50 | }
51 |
52 | server {
53 | listen 80;
54 | server_name demo.sonerezh.bzh/sonerezh;
55 |
56 | index index.php;
57 |
58 | location /sonerezh/ {
59 | alias /var/www/sonerezh/app/webroot/;
60 | try_files $uri $uri/ /sonerezh//sonerezh/index.php?$args;
61 |
62 | # The section below handle the thumbnails cache, on the client (browser)
63 | # side (optional but recommended)
64 | location ~* /([^/]+_[0-9]+x[0-9]+(@[0-9]+x)?\.[a-z]+)$ {
65 | try_files /img/resized/$1 /index.php?$args;
66 | add_header Cache-Control 'public';
67 | expires 14d;
68 | access_log off;
69 | }
70 |
71 | location ~ ^/sonerezh/(.+\.php)$ {
72 | alias /var/www/sonerezh/app/webroot/$1;
73 | fastcgi_pass php-fpm;
74 | include fastcgi.conf;
75 |
76 | # If fastcgi.conf is not available on your platform you may want to
77 | # uncomment the following line
78 | #fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
79 | }
80 | }
81 | }
82 | ```
83 |
--------------------------------------------------------------------------------
/app/Config/email.php.default:
--------------------------------------------------------------------------------
1 | The name of a supported transport; valid options are as follows:
28 | * Mail - Send using PHP mail function
29 | * Smtp - Send using SMTP
30 | * Debug - Do not send the email, just return the result
31 | *
32 | * You can add custom transports (or override existing transports) by adding the
33 | * appropriate file to app/Network/Email. Transports should be named 'YourTransport.php',
34 | * where 'Your' is the name of the transport.
35 | *
36 | * from =>
37 | * The origin email. See CakeEmail::from() about the valid values
38 | *
39 | */
40 | class EmailConfig {
41 |
42 | public $default = array(
43 | 'transport' => 'Mail',
44 | 'from' => 'you@localhost',
45 | //'charset' => 'utf-8',
46 | //'headerCharset' => 'utf-8',
47 | );
48 |
49 | public $smtp = array(
50 | 'transport' => 'Smtp',
51 | 'from' => array('site@localhost' => 'My Site'),
52 | 'host' => 'localhost',
53 | 'port' => 25,
54 | 'timeout' => 30,
55 | 'username' => 'user',
56 | 'password' => 'secret',
57 | 'client' => null,
58 | 'log' => false,
59 | //'charset' => 'utf-8',
60 | //'headerCharset' => 'utf-8',
61 | );
62 |
63 | public $fast = array(
64 | 'from' => 'you@localhost',
65 | 'sender' => null,
66 | 'to' => null,
67 | 'cc' => null,
68 | 'bcc' => null,
69 | 'replyTo' => null,
70 | 'readReceipt' => null,
71 | 'returnPath' => null,
72 | 'messageId' => true,
73 | 'subject' => null,
74 | 'message' => null,
75 | 'headers' => null,
76 | 'viewRender' => null,
77 | 'template' => false,
78 | 'layout' => false,
79 | 'viewVars' => null,
80 | 'attachments' => null,
81 | 'emailFormat' => null,
82 | 'transport' => 'Smtp',
83 | 'host' => 'localhost',
84 | 'port' => 25,
85 | 'timeout' => 30,
86 | 'username' => 'user',
87 | 'password' => 'secret',
88 | 'client' => null,
89 | 'log' => true,
90 | //'charset' => 'utf-8',
91 | //'headerCharset' => 'utf-8',
92 | );
93 |
94 | }
95 |
--------------------------------------------------------------------------------
/app/Plugin/DebugKit/View/Helper/FirePhpToolbarHelper.php:
--------------------------------------------------------------------------------
1 | 'firePHP', 'forceEnable' => false);
32 |
33 | /**
34 | * send method
35 | *
36 | * @return void
37 | */
38 | public function send() {
39 | $view = $this->_View;
40 | $view->element('debug_toolbar', array('disableTimer' => true), array('plugin' => 'DebugKit'));
41 | }
42 |
43 | /**
44 | * makeNeatArray.
45 | *
46 | * wraps FireCake::dump() allowing panel elements to continue functioning
47 | *
48 | * @param string $values
49 | * @return void
50 | */
51 | public function makeNeatArray($values) {
52 | FireCake::info($values);
53 | }
54 |
55 | /**
56 | * Create a simple message
57 | *
58 | * @param string $label Label of message
59 | * @param string $message Message content
60 | * @return void
61 | */
62 | public function message($label, $message) {
63 | FireCake::log($message, $label);
64 | }
65 |
66 | /**
67 | * Generate a table with FireCake
68 | *
69 | * @param array $rows Rows to print
70 | * @param array $headers Headers for table
71 | * @param array $options Additional options and params
72 | * @return void
73 | */
74 | public function table($rows, $headers, $options = array()) {
75 | $title = $headers[0];
76 | if (isset($options['title'])) {
77 | $title = $options['title'];
78 | }
79 | foreach ($rows as $i => $row) {
80 | $rows[$i] = array_values($row);
81 | }
82 | array_unshift($rows, $headers);
83 | FireCake::table($title, $rows);
84 | }
85 |
86 | /**
87 | * Start a panel which is a 'Group' in FirePHP
88 | *
89 | * @param $title
90 | * @param $anchor
91 | * @return void
92 | */
93 | public function panelStart($title, $anchor) {
94 | FireCake::group($title);
95 | }
96 |
97 | /**
98 | * End a panel (Group)
99 | *
100 | * @return void
101 | */
102 | public function panelEnd() {
103 | FireCake::groupEnd();
104 | }
105 |
106 | }
107 |
--------------------------------------------------------------------------------
/app/webroot/js/lazyload.min.js:
--------------------------------------------------------------------------------
1 | /*
2 | lazyload v2.1.3 | github.com/vvo/lazyload#license
3 | */
4 | (function(c,k){function t(a,b,g){a.attachEvent?a.attachEvent("on"+b,g):a.addEventListener(b,g,!1)}function u(a,b,g){var d;return function(){var f=this,c=arguments,e=g&&!d;clearTimeout(d);d=setTimeout(function(){d=null;g||a.apply(f,c)},b);e&&a.apply(f,c)}}function v(a){function b(b,l,e){if(!d(k.documentElement,b)||!d(k.documentElement,a))return e?setTimeout(g(b,l,e),0):!1;var c=b.getBoundingClientRect(),n=a.getBoundingClientRect(),m=c.left,h=c.top,p=l,q=l;a===k.body?(p+=k.documentElement.clientWidth,
5 | q+=k.documentElement.clientHeight,n={bottom:a.scrollHeight,top:0,left:0,right:a.scrollWidth}):(m-=n.left,h-=n.top,p+=a.clientWidth,q+=a.clientHeight);if(!(c.rightn.right||c.bottomn.bottom)&&h<=q&&m<=p)if(e)f.splice(r.call(f,b),1),e(b);else return!0;else if(e)setTimeout(g(b,l,e),0);else return!1}function g(a,g,d){-1===r.call(f,a)&&f.push(a);return function(){l.push(function(){b(a,g,d)})}}var l=[],f=[],e=a===k.body?c:a,m=u(function(){for(var a;a=l.shift();)a()},15);t(e,
6 | "scroll",m);e===c&&t(c,"resize",m);"function"===typeof window.MutationObserver&&h(f,a,m);return{container:a,inViewport:b}}function r(a){for(var b=this.length;b--&&this[b]!==a;);return b}function h(a,b,g){function d(b){return-1!==r.call(a,b)}function e(a){return 0settings[$Model->alias] = array_merge($this->_defaults, $settings);
48 | } else {
49 | $this->settings[$Model->alias] = $this->_defaults;
50 | }
51 | }
52 |
53 | /**
54 | * beforeFind, starts a timer for a find operation.
55 | *
56 | * @param Model $Model
57 | * @param array $queryData Array of query data (not modified)
58 | * @return boolean true
59 | */
60 | public function beforeFind(Model $Model, $queryData) {
61 | DebugKitDebugger::startTimer($Model->alias . '_find', $Model->alias . '->find()');
62 | return true;
63 | }
64 |
65 | /**
66 | * afterFind, stops a timer for a find operation.
67 | *
68 | * @param Model $Model
69 | * @param array $results Array of results
70 | * @param $primary
71 | * @return boolean true.
72 | */
73 | public function afterFind(Model $Model, $results, $primary = false) {
74 | DebugKitDebugger::stopTimer($Model->alias . '_find');
75 | return true;
76 | }
77 |
78 | /**
79 | * beforeSave, starts a time before a save is initiated.
80 | *
81 | * @param Model $Model
82 | * @param array $options
83 | * @return boolean true
84 | */
85 | public function beforeSave(Model $Model, $options = array()) {
86 | DebugKitDebugger::startTimer($Model->alias . '_save', $Model->alias . '->save()');
87 | return true;
88 | }
89 |
90 | /**
91 | * afterSave, stop the timer started from a save.
92 | *
93 | * @param \Model $Model
94 | * @param string $created
95 | * @return boolean Always true
96 | */
97 | public function afterSave(Model $Model, $created, $options = array()) {
98 | DebugKitDebugger::stopTimer($Model->alias . '_save');
99 | return true;
100 | }
101 |
102 | }
103 |
--------------------------------------------------------------------------------
/app/Plugin/DebugKit/Console/Command/WhitespaceShell.php:
--------------------------------------------------------------------------------
1 | params['path']) && strpos($this->params['path'], '/') === 0) {
34 | $path = $this->params['path'];
35 | } elseif (!empty($this->params['path'])) {
36 | $path .= $this->params['path'];
37 | }
38 | $folder = new Folder($path);
39 |
40 | $r = $folder->findRecursive('.*\.php');
41 | $this->out("Checking *.php in " . $path);
42 | foreach ($r as $file) {
43 | $c = file_get_contents($file);
44 | if (preg_match('/^[\n\r|\n\r|\n|\r|\s]+\<\?php/', $c)) {
45 | $this->out('!!!contains leading whitespaces: ' . $this->shortPath($file));
46 | }
47 | if (preg_match('/\?\>[\n\r|\n\r|\n|\r|\s]+$/', $c)) {
48 | $this->out('!!!contains trailing whitespaces: ' . $this->shortPath($file));
49 | }
50 | }
51 | }
52 |
53 | /**
54 | * Much like main() except files are modified. Be sure to have
55 | * backups or use version control.
56 | *
57 | * @return void
58 | */
59 | public function trim() {
60 | $path = APP;
61 | if (!empty($this->params['path']) && strpos($this->params['path'], '/') === 0) {
62 | $path = $this->params['path'];
63 | } elseif (!empty($this->params['path'])) {
64 | $path .= $this->params['path'];
65 | }
66 | $folder = new Folder($path);
67 |
68 | $r = $folder->findRecursive('.*\.php');
69 | $this->out("Checking *.php in " . $path);
70 | foreach ($r as $file) {
71 | $c = file_get_contents($file);
72 | if (preg_match('/^[\n\r|\n\r|\n|\r|\s]+\<\?php/', $c) || preg_match('/\?\>[\n\r|\n\r|\n|\r|\s]+$/', $c)) {
73 | $this->out('trimming' . $this->shortPath($file));
74 | $c = preg_replace('/^[\n\r|\n\r|\n|\r|\s]+\<\?php/', '[\n\r|\n\r|\n|\r|\s]+$/', '?>', $c);
76 | file_put_contents($file, $c);
77 | }
78 | }
79 | }
80 |
81 | /**
82 | * get the option parser
83 | *
84 | * @return ConsoleOptionParser
85 | */
86 | public function getOptionParser() {
87 | $parser = parent::getOptionParser();
88 | return $parser->addOption('path', array(
89 | 'short' => 'p',
90 | 'help' => __d('cake_console', 'Absolute path or relative to APP.')
91 | ));
92 | }
93 | }
94 |
--------------------------------------------------------------------------------
/app/webroot/js/jquery.list.js:
--------------------------------------------------------------------------------
1 | (function($) {
2 | $.fn.list = function(options) {
3 |
4 | var settings = $.extend({
5 | min: 1,
6 | table: '',
7 | cellTemplate: '',
8 | updateTemplate: function() {},
9 | callback: function() {},
10 | cellHeight: 20,
11 | cellsShowed: 10,
12 | data: []
13 | }, options);
14 |
15 | var totalSize = settings.data.length * settings.cellHeight;
16 | var lastIndex = 0;
17 | var maxHeight = totalSize-(settings.cellsShowed * settings.cellHeight);
18 | var maxIndex = settings.data.length - settings.cellsShowed;
19 |
20 | $(settings.table + " tbody", this).append(' ');
21 | var max = Math.min(settings.data.length, settings.cellsShowed);
22 | for(var i = 0; i < max; i++) {
23 | var $template = settings.updateTemplate($(settings.cellTemplate), settings.data[i], i);
24 | $(settings.table + " tbody", this).append($template);
25 | }
26 | $(settings.table + " tbody", this).append(' ');
27 |
28 | this.unbind('scroll');
29 | this.scroll(function() {
30 | var index = Math.floor($(this).scrollTop()/settings.cellHeight)-settings.min;
31 | if(index < settings.min && index < lastIndex) {
32 | index = 0;
33 | }
34 | if(index >= 0 && index != lastIndex) {
35 | var topSize = index * settings.cellHeight;
36 | var bottomSize = totalSize - (index + settings.cellsShowed) * settings.cellHeight;
37 |
38 | if(topSize > maxHeight) {
39 | topSize = maxHeight;
40 | }
41 |
42 | $(settings.table, this).find('.first-line').height(topSize);
43 | $(settings.table, this).find('.last-line').height(bottomSize);
44 |
45 | if(index > maxIndex) {
46 | index = maxIndex;
47 | }
48 |
49 | var diff = index - lastIndex;
50 | if(diff > 0) {
51 | for(var i = 0; i < diff; i++) {
52 | var $tr = $(settings.table, this).find('tr:eq(1)');
53 | var realIndex = index-diff+i+settings.cellsShowed;
54 | $tr = settings.updateTemplate($tr, settings.data[realIndex], realIndex);
55 | $(settings.table, this).find('.last-line').before($tr);
56 | }
57 | }else {
58 | for(var i = 0; i > diff; i--) {
59 | var $tr = $(settings.table, this).find('tr:eq('+settings.cellsShowed+')');
60 | var realIndex = index-diff+i-1;
61 | $tr = settings.updateTemplate($tr, settings.data[realIndex], realIndex);
62 | $(settings.table, this).find('.first-line').after($tr);
63 | }
64 | }
65 | settings.callback();
66 | lastIndex = index;
67 | }
68 |
69 | });
70 | }
71 | }(jQuery));
--------------------------------------------------------------------------------
/app/Config/database.php.default:
--------------------------------------------------------------------------------
1 | The name of a supported datasource; valid options are as follows:
25 | * Database/Mysql - MySQL 4 & 5,
26 | * Database/Sqlite - SQLite (PHP5 only),
27 | * Database/Postgres - PostgreSQL 7 and higher,
28 | * Database/Sqlserver - Microsoft SQL Server 2005 and higher
29 | *
30 | * You can add custom database datasources (or override existing datasources) by adding the
31 | * appropriate file to app/Model/Datasource/Database. Datasources should be named 'MyDatasource.php',
32 | *
33 | *
34 | * persistent => true / false
35 | * Determines whether or not the database should use a persistent connection
36 | *
37 | * host =>
38 | * the host you connect to the database. To add a socket or port number, use 'port' => #
39 | *
40 | * prefix =>
41 | * Uses the given prefix for all the tables in this database. This setting can be overridden
42 | * on a per-table basis with the Model::$tablePrefix property.
43 | *
44 | * schema =>
45 | * For Postgres/Sqlserver specifies which schema you would like to use the tables in.
46 | * Postgres defaults to 'public'. For Sqlserver, it defaults to empty and use
47 | * the connected user's default schema (typically 'dbo').
48 | *
49 | * encoding =>
50 | * For MySQL, Postgres specifies the character encoding to use when connecting to the
51 | * database. Uses database default not specified.
52 | *
53 | * unix_socket =>
54 | * For MySQL to connect via socket specify the `unix_socket` parameter instead of `host` and `port`
55 | *
56 | * settings =>
57 | * Array of key/value pairs, on connection it executes SET statements for each pair
58 | * For MySQL : http://dev.mysql.com/doc/refman/5.6/en/set-statement.html
59 | * For Postgres : http://www.postgresql.org/docs/9.2/static/sql-set.html
60 | * For Sql Server : http://msdn.microsoft.com/en-us/library/ms190356.aspx
61 | */
62 | class DATABASE_CONFIG {
63 |
64 | public $default = array(
65 | 'datasource' => 'Database/Mysql',
66 | 'persistent' => false,
67 | 'host' => 'localhost',
68 | 'login' => 'user',
69 | 'password' => 'password',
70 | 'database' => 'database_name',
71 | 'prefix' => '',
72 | //'encoding' => 'utf8',
73 | );
74 |
75 | public $test = array(
76 | 'datasource' => 'Database/Mysql',
77 | 'persistent' => false,
78 | 'host' => 'localhost',
79 | 'login' => 'user',
80 | 'password' => 'password',
81 | 'database' => 'test_database_name',
82 | 'prefix' => '',
83 | //'encoding' => 'utf8',
84 | );
85 | }
86 |
--------------------------------------------------------------------------------