Add integrated FTP upload support.

This commit is contained in:
Buster Neece 2019-08-25 17:50:20 -05:00
parent 421926970c
commit 1a1a18dfe7
No known key found for this signature in database
GPG Key ID: 6D9E12FF03411F4E
13 changed files with 469 additions and 108 deletions

3
.env
View File

@ -2,3 +2,6 @@ COMPOSE_PROJECT_NAME=azuracast
AZURACAST_HTTP_PORT=80
AZURACAST_HTTPS_PORT=443
AZURACAST_FTP_PORT=21
AZURACAST_FTP_PASV_RANGE=30000-30009

View File

@ -39,6 +39,7 @@ return function (\Azura\EventDispatcher $dispatcher)
new Command\Internal\DjOn,
new Command\Internal\DjOff,
new Command\Internal\Feedback,
new Command\Internal\FtpAuth,
// Locales
new Command\LocaleGenerate,

View File

@ -90,6 +90,8 @@ return [
'security' => [
'legend' => __('Security Controls'),
'use_grid' => true,
'elements' => [
Entity\Settings::ALWAYS_USE_SSL => [
@ -100,6 +102,19 @@ return [
'selected_text' => __('Yes'),
'deselected_text' => __('No'),
'default' => false,
'form_group_class' => 'col-md-6',
]
],
Entity\Settings::ENABLE_FTP_SERVER => [
'toggle',
[
'label' => __('Enable Built-in FTP Server'),
'description' => __('If enabled, users can connect via FTP using their AzuraCast credentials to upload media directly to any stations they manage.'),
'selected_text' => __('Yes'),
'deselected_text' => __('No'),
'default' => true,
'form_group_class' => 'col-md-6',
]
],
@ -110,6 +125,7 @@ return [
'class' => 'advanced',
'description' => __('<a href="%s" target="_blank">Learn more about this header</a>. Set to * to allow all sources, or specify a list of origins separated by a comma (,).', 'https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Origin'),
'default' => '',
'form_group_class' => 'col-md-12',
]
],

View File

@ -15,16 +15,12 @@ services:
- /var/run/docker.sock:/tmp/docker.sock:ro
depends_on:
- web
restart: always
web:
image: azuracast/azuracast_web_v2:latest
build:
context: ../docker-azuracast-web-v2
# Want to customize the HTTP/S ports? Follow the instructions here:
# https://github.com/AzuraCast/AzuraCast/blob/master/SUPPORT.md#use-non-standard-ports
ports:
- '${AZURACAST_HTTP_PORT:-80}:80'
- '${AZURACAST_HTTPS_PORT:-443}:443'
depends_on:
- mariadb
- influxdb
@ -33,7 +29,10 @@ services:
env_file: azuracast.env
environment: &default-environment
LANG: ${LANG:-en_US.UTF-8}
AZURACAST_DC_REVISION: 5
AZURACAST_DC_REVISION: 6
AZURACAST_FTP_PORT: ${AZURACAST_FTP_PORT:-21}
ports:
- '${AZURACAST_FTP_PORT:-21}:21'
volumes:
- letsencrypt:/etc/letsencrypt
- .:/var/azuracast/www

View File

@ -27,6 +27,7 @@ services:
DEFAULT_HOST: azuracast.local
depends_on:
- web
restart: always
nginx_proxy_letsencrypt:
image: jrcs/letsencrypt-nginx-proxy-companion:latest
@ -34,6 +35,7 @@ services:
- nginx_proxy
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro
restart: always
volumes:
letsencrypt_html: {}

View File

@ -19,6 +19,8 @@ services:
ports:
- '${AZURACAST_HTTP_PORT:-80}:80'
- '${AZURACAST_HTTPS_PORT:-443}:443'
- '${AZURACAST_FTP_PORT:-21}:21'
- '30000-30009:30000-30009' # FTP PASV support
depends_on:
- mariadb
- influxdb
@ -27,7 +29,8 @@ services:
env_file: azuracast.env
environment: &default-environment
LANG: ${LANG:-en_US.UTF-8}
AZURACAST_DC_REVISION: 5
AZURACAST_DC_REVISION: 6
AZURACAST_FTP_PORT: ${AZURACAST_FTP_PORT:-21}
volumes:
- letsencrypt:/etc/letsencrypt
- www_data:/var/azuracast/www

View File

@ -7,8 +7,8 @@ msgstr ""
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"POT-Creation-Date: 2019-08-21T22:24:59+00:00\n"
"PO-Revision-Date: 2019-08-21T22:24:59+00:00\n"
"POT-Creation-Date: 2019-08-25T22:49:39+00:00\n"
"PO-Revision-Date: 2019-08-25T22:49:39+00:00\n"
"Language: \n"
#: /var/azuracast/www/src/Acl.php:184
@ -620,7 +620,7 @@ msgstr ""
#: /var/azuracast/www/src/Controller/Stations/Reports/OverviewController.php:119
#: /var/azuracast/www/src/Controller/Stations/Reports/OverviewController.php:169
#: /var/azuracast/www/config/menus/station.php:102
#: /var/azuracast/www/templates/frontend/index/index.phtml:124
#: /var/azuracast/www/templates/frontend/index/index.phtml:120
#: /var/azuracast/www/templates/frontend/index/index_metrics.js.phtml:32
#: /var/azuracast/www/templates/stations/profile/panel_nowplaying.phtml:18
#: /var/azuracast/www/templates/stations/profile/panel_streams.phtml:28
@ -701,7 +701,7 @@ msgid "Automated assignment error"
msgstr ""
#: /var/azuracast/www/src/Controller/Stations/Files/BatchController.php:230
#: /var/azuracast/www/src/Controller/Stations/Files/FilesController.php:150
#: /var/azuracast/www/src/Controller/Stations/Files/FilesController.php:159
msgid "Path \"%s\" is not a folder."
msgstr ""
@ -721,20 +721,20 @@ msgstr ""
msgid "Edit Media"
msgstr ""
#: /var/azuracast/www/src/Controller/Stations/Files/FilesController.php:125
#: /var/azuracast/www/src/Controller/Stations/Files/FilesController.php:134
msgid "File renamed!"
msgstr ""
#: /var/azuracast/www/src/Controller/Stations/Files/FilesController.php:135
#: /var/azuracast/www/src/Controller/Stations/Files/FilesController.php:144
msgid "Rename File/Directory"
msgstr ""
#: /var/azuracast/www/src/Controller/Stations/Files/FilesController.php:207
#: /var/azuracast/www/src/Controller/Stations/Files/FilesController.php:216
msgid "This station is out of available storage space."
msgstr ""
#: /var/azuracast/www/src/Controller/Stations/Files/ListController.php:122
#: /var/azuracast/www/templates/stations/files/index.phtml:179
#: /var/azuracast/www/templates/stations/files/index.phtml:184
msgid "Directory"
msgstr ""
@ -1004,7 +1004,7 @@ msgstr ""
#: /var/azuracast/www/config/forms/install_shoutcast.php:35
#: /var/azuracast/www/config/forms/media.php:57
#: /var/azuracast/www/config/forms/playlist.php:121
#: /var/azuracast/www/templates/stations/files/index.phtml:54
#: /var/azuracast/www/templates/stations/files/index.phtml:59
msgid "Select File"
msgstr ""
@ -1190,7 +1190,7 @@ msgstr ""
#: /var/azuracast/www/config/forms/remote.php:184
#: /var/azuracast/www/config/forms/rename.php:18
#: /var/azuracast/www/config/forms/role.php:46
#: /var/azuracast/www/config/forms/settings.php:184
#: /var/azuracast/www/config/forms/settings.php:200
#: /var/azuracast/www/config/forms/song.php:53
#: /var/azuracast/www/config/forms/station.php:492
#: /var/azuracast/www/config/forms/streamer.php:63
@ -1278,8 +1278,9 @@ msgstr ""
#: /var/azuracast/www/config/forms/settings.php:39
#: /var/azuracast/www/config/forms/settings.php:51
#: /var/azuracast/www/config/forms/settings.php:81
#: /var/azuracast/www/config/forms/settings.php:100
#: /var/azuracast/www/config/forms/settings.php:168
#: /var/azuracast/www/config/forms/settings.php:102
#: /var/azuracast/www/config/forms/settings.php:114
#: /var/azuracast/www/config/forms/settings.php:184
#: /var/azuracast/www/config/forms/station.php:84
#: /var/azuracast/www/config/forms/station.php:261
#: /var/azuracast/www/config/forms/station.php:273
@ -1314,8 +1315,9 @@ msgstr ""
#: /var/azuracast/www/config/forms/settings.php:40
#: /var/azuracast/www/config/forms/settings.php:52
#: /var/azuracast/www/config/forms/settings.php:82
#: /var/azuracast/www/config/forms/settings.php:101
#: /var/azuracast/www/config/forms/settings.php:169
#: /var/azuracast/www/config/forms/settings.php:103
#: /var/azuracast/www/config/forms/settings.php:115
#: /var/azuracast/www/config/forms/settings.php:185
#: /var/azuracast/www/config/forms/station.php:85
#: /var/azuracast/www/config/forms/station.php:262
#: /var/azuracast/www/config/forms/station.php:274
@ -1509,6 +1511,7 @@ msgstr ""
#: /var/azuracast/www/templates/frontend/account/login.phtml:41
#: /var/azuracast/www/templates/frontend/public/dj.js.phtml:25
#: /var/azuracast/www/templates/frontend/setup/register.phtml:47
#: /var/azuracast/www/templates/stations/files/index.phtml:255
#: /var/azuracast/www/templates/stations/streamers/index.phtml:81
msgid "Password"
msgstr ""
@ -1987,7 +1990,7 @@ msgstr ""
#: /var/azuracast/www/config/forms/station.php:37
#: /var/azuracast/www/config/forms/user.php:10
#: /var/azuracast/www/templates/admin/custom_fields/index.phtml:22
#: /var/azuracast/www/templates/stations/files/index.phtml:113
#: /var/azuracast/www/templates/stations/files/index.phtml:118
#: /var/azuracast/www/templates/stations/webhooks/index.phtml:25
msgid "Name"
msgstr ""
@ -2218,87 +2221,95 @@ msgstr ""
msgid "Security Controls"
msgstr ""
#: /var/azuracast/www/config/forms/settings.php:98
#: /var/azuracast/www/config/forms/settings.php:100
msgid "Always Use HTTPS"
msgstr ""
#: /var/azuracast/www/config/forms/settings.php:99
#: /var/azuracast/www/config/forms/settings.php:101
msgid "Set to \"Yes\" to always use \"https://\" secure URLs, and to automatically redirect to the secure URL when an insecure URL is visited."
msgstr ""
#: /var/azuracast/www/config/forms/settings.php:109
#: /var/azuracast/www/config/forms/settings.php:112
msgid "Enable Built-in FTP Server"
msgstr ""
#: /var/azuracast/www/config/forms/settings.php:113
msgid "If enabled, users can connect via FTP using their AzuraCast credentials to upload media directly to any stations they manage."
msgstr ""
#: /var/azuracast/www/config/forms/settings.php:124
msgid "API \"Access-Control-Allow-Origin\" header"
msgstr ""
#: /var/azuracast/www/config/forms/settings.php:111
#: /var/azuracast/www/config/forms/settings.php:126
msgid "<a href=\"%s\" target=\"_blank\">Learn more about this header</a>. Set to * to allow all sources, or specify a list of origins separated by a comma (,)."
msgstr ""
#: /var/azuracast/www/config/forms/settings.php:120
#: /var/azuracast/www/config/forms/settings.php:136
msgid "Privacy Controls"
msgstr ""
#: /var/azuracast/www/config/forms/settings.php:121
#: /var/azuracast/www/config/forms/settings.php:137
msgid "AzuraCast does not send your station or listener data to any external server. You can control how much data AzuraCast logs about your listeners here."
msgstr ""
#: /var/azuracast/www/config/forms/settings.php:128
#: /var/azuracast/www/config/forms/settings.php:144
msgid "Listener Analytics Collection"
msgstr ""
#: /var/azuracast/www/config/forms/settings.php:129
#: /var/azuracast/www/config/forms/settings.php:145
msgid "Aggregate listener statistics are used to show station reports across the system. IP-based listener statistics are used to view live listener tracking and may be required for royalty reports."
msgstr ""
#: /var/azuracast/www/config/forms/settings.php:132
#: /var/azuracast/www/config/forms/settings.php:148
msgid "<b>Full:</b> Collect aggregate listener statistics and IP-based listener statistics"
msgstr ""
#: /var/azuracast/www/config/forms/settings.php:133
#: /var/azuracast/www/config/forms/settings.php:149
msgid "<b>Limited:</b> Only collect aggregate listener statistics"
msgstr ""
#: /var/azuracast/www/config/forms/settings.php:134
#: /var/azuracast/www/config/forms/settings.php:150
msgid "<b>None:</b> Do not collect any listener analytics"
msgstr ""
#: /var/azuracast/www/config/forms/settings.php:143
#: /var/azuracast/www/config/forms/settings.php:159
msgid "AzuraCast Installation Telemetry"
msgstr ""
#: /var/azuracast/www/config/forms/settings.php:144
#: /var/azuracast/www/config/forms/settings.php:160
msgid "Choose whether your installation communicates with central AzuraCast servers to check for updates and announcements.<br>AzuraCast respects your privacy; see our <a href=\"%s\" target=\"_blank\">privacy policy</a> for more details."
msgstr ""
#: /var/azuracast/www/config/forms/settings.php:151
#: /var/azuracast/www/config/forms/settings.php:167
msgid "Check for Updates and Announcements"
msgstr ""
#: /var/azuracast/www/config/forms/settings.php:152
#: /var/azuracast/www/config/forms/settings.php:168
msgid "Send minimal details about your AzuraCast installation to the AzuraCast central server to check for updated software releases and important announcements."
msgstr ""
#: /var/azuracast/www/config/forms/settings.php:155
#: /var/azuracast/www/config/forms/settings.php:171
msgid "<b>None:</b> Do not check for updates or announcements."
msgstr ""
#: /var/azuracast/www/config/forms/settings.php:156
#: /var/azuracast/www/config/forms/settings.php:172
msgid "<b>Release Only:</b> Critical announcements and new release versions only."
msgstr ""
#: /var/azuracast/www/config/forms/settings.php:157
#: /var/azuracast/www/config/forms/settings.php:173
msgid "<b>All Updates:</b> Include all announcements and minor updates."
msgstr ""
#: /var/azuracast/www/config/forms/settings.php:166
#: /var/azuracast/www/config/forms/settings.php:182
msgid "Automatically Send Error Reports to AzuraCast"
msgstr ""
#: /var/azuracast/www/config/forms/settings.php:167
#: /var/azuracast/www/config/forms/settings.php:183
msgid "If the web application encounters an error, you can choose to automatically send an anonymized report of the error to the AzuraCast team for faster diagnosis and resolution."
msgstr ""
#: /var/azuracast/www/config/forms/settings.php:167
#: /var/azuracast/www/config/forms/settings.php:183
msgid "Error reports are powered by <a href=\"%s\" target=\"_blank\">%s</a>."
msgstr ""
@ -2332,7 +2343,7 @@ msgstr ""
#: /var/azuracast/www/config/forms/station.php:25
#: /var/azuracast/www/templates/admin/index/index.phtml:18
#: /var/azuracast/www/templates/admin/sidebar.phtml:3
#: /var/azuracast/www/templates/frontend/index/index.phtml:59
#: /var/azuracast/www/templates/frontend/index/index.phtml:55
msgid "Administration"
msgstr ""
@ -2762,7 +2773,7 @@ msgstr ""
#: /var/azuracast/www/templates/frontend/public/dj.js.phtml:27
#: /var/azuracast/www/templates/frontend/public/embedrequests.phtml:20
#: /var/azuracast/www/templates/frontend/public/index.phtml:75
#: /var/azuracast/www/templates/stations/files/index.phtml:114
#: /var/azuracast/www/templates/stations/files/index.phtml:119
#: /var/azuracast/www/templates/stations/playlists/reorder.phtml:26
#: /var/azuracast/www/templates/stations/reports/performance.phtml:30
msgid "Title"
@ -3031,7 +3042,7 @@ msgid "Music Files"
msgstr ""
#: /var/azuracast/www/config/menus/station.php:53
#: /var/azuracast/www/templates/stations/files/index.phtml:123
#: /var/azuracast/www/templates/stations/files/index.phtml:128
#: /var/azuracast/www/templates/stations/playlists/index.phtml:4
#: /var/azuracast/www/templates/stations/playlists/index.phtml:17
#: /var/azuracast/www/templates/stations/profile/panel_backend.phtml:34
@ -3236,7 +3247,7 @@ msgstr ""
#: /var/azuracast/www/templates/admin/users/index.phtml:37
#: /var/azuracast/www/templates/admin/users/index.phtml:39
#: /var/azuracast/www/templates/stations/files/index.js.phtml:27
#: /var/azuracast/www/templates/stations/files/index.phtml:101
#: /var/azuracast/www/templates/stations/files/index.phtml:106
#: /var/azuracast/www/templates/stations/mounts/index.phtml:36
#: /var/azuracast/www/templates/stations/playlists/index.phtml:66
#: /var/azuracast/www/templates/stations/queue/index.js.phtml:36
@ -3312,8 +3323,8 @@ msgstr ""
#: /var/azuracast/www/templates/admin/users/index.phtml:21
#: /var/azuracast/www/templates/frontend/public/embedrequests.phtml:23
#: /var/azuracast/www/templates/frontend/public/index.phtml:78
#: /var/azuracast/www/templates/stations/files/index.phtml:124
#: /var/azuracast/www/templates/stations/files/index.phtml:180
#: /var/azuracast/www/templates/stations/files/index.phtml:129
#: /var/azuracast/www/templates/stations/files/index.phtml:185
#: /var/azuracast/www/templates/stations/mounts/index.phtml:24
#: /var/azuracast/www/templates/stations/playlists/index.phtml:54
#: /var/azuracast/www/templates/stations/playlists/reorder.phtml:29
@ -3383,7 +3394,7 @@ msgid "Last Modified"
msgstr ""
#: /var/azuracast/www/templates/admin/backups/index.phtml:102
#: /var/azuracast/www/templates/stations/files/index.phtml:121
#: /var/azuracast/www/templates/stations/files/index.phtml:126
msgid "Size"
msgstr ""
@ -3484,7 +3495,7 @@ msgid "Manage Stations"
msgstr ""
#: /var/azuracast/www/templates/admin/stations/index.phtml:10
#: /var/azuracast/www/templates/frontend/index/index.phtml:108
#: /var/azuracast/www/templates/frontend/index/index.phtml:104
msgid "Add Station"
msgstr ""
@ -3493,7 +3504,7 @@ msgid "Station"
msgstr ""
#: /var/azuracast/www/templates/admin/stations/index.phtml:29
#: /var/azuracast/www/templates/frontend/index/index.phtml:152
#: /var/azuracast/www/templates/frontend/index/index.phtml:148
#: /var/azuracast/www/templates/stations/profile/panel_streamers.phtml:26
msgid "Manage"
msgstr ""
@ -3618,31 +3629,31 @@ msgstr ""
msgid "Dashboard"
msgstr ""
#: /var/azuracast/www/templates/frontend/index/index.phtml:44
#: /var/azuracast/www/templates/frontend/index/index.phtml:40
msgid "AzuraCast User"
msgstr ""
#: /var/azuracast/www/templates/frontend/index/index.phtml:54
#: /var/azuracast/www/templates/frontend/index/index.phtml:50
#: /var/azuracast/www/templates/frontend/profile/index.phtml:2
#: /var/azuracast/www/templates/frontend/profile/index.phtml:20
#: /var/azuracast/www/templates/main.phtml:79
msgid "My Account"
msgstr ""
#: /var/azuracast/www/templates/frontend/index/index.phtml:90
#: /var/azuracast/www/templates/frontend/index/index.phtml:93
#: /var/azuracast/www/templates/frontend/index/index.phtml:86
#: /var/azuracast/www/templates/frontend/index/index.phtml:89
msgid "Listeners Per Station"
msgstr ""
#: /var/azuracast/www/templates/frontend/index/index.phtml:102
#: /var/azuracast/www/templates/frontend/index/index.phtml:98
msgid "Station Overview"
msgstr ""
#: /var/azuracast/www/templates/frontend/index/index.phtml:123
#: /var/azuracast/www/templates/frontend/index/index.phtml:119
msgid "Station Name"
msgstr ""
#: /var/azuracast/www/templates/frontend/index/index.phtml:125
#: /var/azuracast/www/templates/frontend/index/index.phtml:121
#: /var/azuracast/www/templates/stations/profile/panel_nowplaying.phtml:30
msgid "Now Playing"
msgstr ""
@ -3745,6 +3756,7 @@ msgid "DJ Credentials"
msgstr ""
#: /var/azuracast/www/templates/frontend/public/dj.js.phtml:24
#: /var/azuracast/www/templates/stations/files/index.phtml:247
#: /var/azuracast/www/templates/stations/streamers/index.phtml:25
msgid "Username"
msgstr ""
@ -3756,7 +3768,7 @@ msgstr ""
#: /var/azuracast/www/templates/frontend/public/dj.js.phtml:28
#: /var/azuracast/www/templates/frontend/public/embedrequests.phtml:21
#: /var/azuracast/www/templates/frontend/public/index.phtml:76
#: /var/azuracast/www/templates/stations/files/index.phtml:115
#: /var/azuracast/www/templates/stations/files/index.phtml:120
#: /var/azuracast/www/templates/stations/playlists/reorder.phtml:27
#: /var/azuracast/www/templates/stations/reports/performance.phtml:31
msgid "Artist"
@ -3809,7 +3821,7 @@ msgstr ""
#: /var/azuracast/www/templates/frontend/public/embedrequests.phtml:22
#: /var/azuracast/www/templates/frontend/public/index.phtml:77
#: /var/azuracast/www/templates/stations/files/index.phtml:116
#: /var/azuracast/www/templates/stations/files/index.phtml:121
#: /var/azuracast/www/templates/stations/playlists/reorder.phtml:28
msgid "Album"
msgstr ""
@ -4031,68 +4043,114 @@ msgstr ""
msgid "%s of %s Used (%d Files)"
msgstr ""
#: /var/azuracast/www/templates/stations/files/index.phtml:43
msgid "You can also upload files in bulk via SFTP by <a href=\"%s\" target=\"_blank\">following these instructions</a>. Newly uploaded files will automatically be processed within a few minutes."
#: /var/azuracast/www/templates/stations/files/index.phtml:44
msgid "You can also upload files in bulk via FTP."
msgstr ""
#: /var/azuracast/www/templates/stations/files/index.phtml:52
#: /var/azuracast/www/templates/stations/files/index.phtml:46
msgid "View connection instructions"
msgstr ""
#: /var/azuracast/www/templates/stations/files/index.phtml:57
msgid "Drag files here to upload to this folder or "
msgstr ""
#: /var/azuracast/www/templates/stations/files/index.phtml:65
#: /var/azuracast/www/templates/stations/files/index.phtml:70
msgid "Set Playlists"
msgstr ""
#: /var/azuracast/www/templates/stations/files/index.phtml:82
#: /var/azuracast/www/templates/stations/files/index.phtml:87
msgid "New Playlist"
msgstr ""
#: /var/azuracast/www/templates/stations/files/index.phtml:87
#: /var/azuracast/www/templates/stations/files/index.phtml:92
msgid "Save"
msgstr ""
#: /var/azuracast/www/templates/stations/files/index.phtml:93
#: /var/azuracast/www/templates/stations/files/index.phtml:98
msgid "Clear Playlists"
msgstr ""
#: /var/azuracast/www/templates/stations/files/index.phtml:97
#: /var/azuracast/www/templates/stations/files/index.phtml:102
msgid "Move"
msgstr ""
#: /var/azuracast/www/templates/stations/files/index.phtml:105
#: /var/azuracast/www/templates/stations/files/index.phtml:110
msgid "New Folder"
msgstr ""
#: /var/azuracast/www/templates/stations/files/index.phtml:117
#: /var/azuracast/www/templates/stations/files/index.phtml:122
#: /var/azuracast/www/templates/stations/reports/duplicates.phtml:26
#: /var/azuracast/www/templates/stations/reports/performance.phtml:33
msgid "Length"
msgstr ""
#: /var/azuracast/www/templates/stations/files/index.phtml:122
#: /var/azuracast/www/templates/stations/files/index.phtml:127
msgid "Modified"
msgstr ""
#: /var/azuracast/www/templates/stations/files/index.phtml:139
#: /var/azuracast/www/templates/stations/files/index.phtml:144
msgid "New Directory"
msgstr ""
#: /var/azuracast/www/templates/stations/files/index.phtml:144
#: /var/azuracast/www/templates/stations/files/index.phtml:149
msgid "Directory Name"
msgstr ""
#: /var/azuracast/www/templates/stations/files/index.phtml:150
#: /var/azuracast/www/templates/stations/files/index.phtml:155
msgid "Create Directory"
msgstr ""
#: /var/azuracast/www/templates/stations/files/index.phtml:162
#: /var/azuracast/www/templates/stations/files/index.phtml:167
msgid "Move {{ selected_files }} File(s) to"
msgstr ""
#: /var/azuracast/www/templates/stations/files/index.phtml:168
#: /var/azuracast/www/templates/stations/files/index.phtml:173
msgid "Back"
msgstr ""
#: /var/azuracast/www/templates/stations/files/index.phtml:207
msgid "FTP Connection Information"
msgstr ""
#: /var/azuracast/www/templates/stations/files/index.phtml:221
#: /var/azuracast/www/templates/stations/streamers/index.phtml:57
#: /var/azuracast/www/templates/stations/streamers/index.phtml:72
msgid "Server"
msgstr ""
#: /var/azuracast/www/templates/stations/files/index.phtml:225
#: /var/azuracast/www/templates/stations/streamers/index.phtml:60
#: /var/azuracast/www/templates/stations/streamers/index.phtml:75
msgid "You may need to connect directly via your IP address, which is <code>%s</code>."
msgstr ""
#: /var/azuracast/www/templates/stations/files/index.phtml:230
#: /var/azuracast/www/templates/stations/streamers/index.phtml:63
#: /var/azuracast/www/templates/stations/streamers/index.phtml:78
msgid "Port"
msgstr ""
#: /var/azuracast/www/templates/stations/files/index.phtml:238
msgid "Protocol"
msgstr ""
#: /var/azuracast/www/templates/stations/files/index.phtml:241
msgid "FTP with Explicit TLS (FTPS)"
msgstr ""
#: /var/azuracast/www/templates/stations/files/index.phtml:242
msgid "Unencrypted FTP is also allowed, but not recommended."
msgstr ""
#: /var/azuracast/www/templates/stations/files/index.phtml:250
msgid "Your AzuraCast E-mail Address"
msgstr ""
#: /var/azuracast/www/templates/stations/files/index.phtml:258
msgid "Your AzuraCast Password"
msgstr ""
#: /var/azuracast/www/templates/stations/logs/index.phtml:12
msgid "Available Logs"
msgstr ""
@ -4603,21 +4661,6 @@ msgstr ""
msgid "IceCast Clients"
msgstr ""
#: /var/azuracast/www/templates/stations/streamers/index.phtml:57
#: /var/azuracast/www/templates/stations/streamers/index.phtml:72
msgid "Server"
msgstr ""
#: /var/azuracast/www/templates/stations/streamers/index.phtml:60
#: /var/azuracast/www/templates/stations/streamers/index.phtml:75
msgid "You may need to connect directly via your IP address, which is <code>%s</code>."
msgstr ""
#: /var/azuracast/www/templates/stations/streamers/index.phtml:63
#: /var/azuracast/www/templates/stations/streamers/index.phtml:78
msgid "Port"
msgstr ""
#: /var/azuracast/www/templates/stations/streamers/index.phtml:66
msgid "Mount Name"
msgstr ""

View File

@ -0,0 +1,37 @@
<?php
namespace App\Console\Command\Internal;
use App\Service\Ftp;
use Azura\Console\Command\CommandAbstract;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
class FtpAuth extends CommandAbstract
{
/**
* {@inheritdoc}
*/
protected function configure()
{
$this->setName('azuracast:internal:ftp-auth')
->setDescription('Authenticate a user for PureFTPD');
}
/**
* {@inheritdoc}
*/
protected function execute(InputInterface $input, OutputInterface $output)
{
$username = getenv('AUTHD_ACCOUNT');
$password = getenv('AUTHD_PASSWORD');
/** @var Ftp $ftp */
$ftp = $this->get(Ftp::class);
$ftp_output = $ftp->auth($username, $password);
foreach($ftp_output as $output_ln) {
$output->writeln($output_ln);
}
return null;
}
}

View File

@ -6,7 +6,9 @@ use App\Form\Form;
use App\Http\Response;
use App\Http\ServerRequest;
use App\Radio\Filesystem;
use App\Service\Ftp;
use Azura\Config;
use Azura\Settings;
use Doctrine\ORM\EntityManager;
use Psr\Http\Message\ResponseInterface;
@ -21,19 +23,25 @@ class FilesController extends FilesControllerAbstract
/** @var array */
protected $form_config;
/** @var Ftp */
protected $ftp;
/**
* @param EntityManager $em
* @param Filesystem $filesystem
* @param Config $config
* @param Ftp $ftp
*/
public function __construct(
EntityManager $em,
Filesystem $filesystem,
Config $config
Config $config,
Ftp $ftp
) {
$this->em = $em;
$this->filesystem = $filesystem;
$this->form_config = $config->get('forms/rename');
$this->ftp = $ftp;
}
public function __invoke(ServerRequest $request, Response $response, $station_id): ResponseInterface
@ -63,6 +71,7 @@ class FilesController extends FilesControllerAbstract
}
return $request->getView()->renderToResponse($response, 'stations/files/index', [
'ftp_info' => $this->ftp->getInfo(),
'playlists' => $playlists,
'custom_fields' => $custom_fields,
'space_used' => $station->getStorageUsed(),

View File

@ -12,15 +12,15 @@ class Settings
// Predefined settings constants.
public const BASE_URL = 'base_url';
public const INSTANCE_NAME = 'instance_name';
public const TIMEZONE = 'timezone';
public const PREFER_BROWSER_URL = 'prefer_browser_url';
public const USE_RADIO_PROXY = 'use_radio_proxy';
public const HISTORY_KEEP_DAYS = 'history_keep_days';
public const ENABLE_FTP_SERVER = 'enable_ftp_server';
public const ALWAYS_USE_SSL = 'always_use_ssl';
public const API_ACCESS_CONTROL = 'api_access_control';
public const NOWPLAYING_USE_WEBSOCKETS = 'nowplaying_use_websockets';
public const LISTENER_ANALYTICS = 'analytics';

160
src/Service/Ftp.php Normal file
View File

@ -0,0 +1,160 @@
<?php
namespace App\Service;
use App\Acl;
use App\Entity;
use App\Http\Router;
use App\Utilities;
use Azura\Settings;
use Doctrine\ORM\EntityManager;
use Psr\Log\LoggerInterface;
class Ftp
{
/** @var AzuraCastCentral */
protected $ac_central;
/** @var Acl */
protected $acl;
/** @var Settings */
protected $app_settings;
/** @var EntityManager */
protected $em;
/** @var Entity\Repository\UserRepository */
protected $user_repo;
/** @var Entity\Repository\SettingsRepository */
protected $settings_repo;
/** @var LoggerInterface */
protected $logger;
/** @var Router */
protected $router;
/**
* @param AzuraCastCentral $ac_central
* @param Acl $acl
* @param Settings $app_settings
* @param EntityManager $em
* @param LoggerInterface $logger
* @param Router $router
*/
public function __construct(
AzuraCastCentral $ac_central,
Acl $acl,
Settings $app_settings,
EntityManager $em,
LoggerInterface $logger,
Router $router
) {
$this->ac_central = $ac_central;
$this->acl = $acl;
$this->app_settings = $app_settings;
$this->em = $em;
$this->logger = $logger;
$this->router = $router;
$this->user_repo = $em->getRepository(Entity\User::class);
$this->settings_repo = $em->getRepository(Entity\Settings::class);
}
/**
* Given a username and password, handle a PureFTPD authentication request.
*
* @param string $username
* @param string $password
* @return array
*/
public function auth(string $username, string $password): array
{
$error = ['auth_ok:-1', 'end'];
if (!$this->isEnabled()) {
return $error;
}
$this->logger->info('FTP Authentication attempt.', [
'username' => $username,
'password' => $password,
]);
$user = $this->user_repo->authenticate($username, $password);
if (!($user instanceof Entity\User)) {
return $error;
}
// Create a temporary directory with symlinks to every station that user can manage.
$ftp_dir = '/tmp/azuracast_ftp_directories/user_'.$user->getId();
Utilities::rmdirRecursive($ftp_dir);
if (!mkdir($ftp_dir) && !is_dir($ftp_dir)) {
throw new \RuntimeException(sprintf('Directory "%s" was not created', $ftp_dir));
}
$stations = $this->em->getRepository(Entity\Station::class)->findAll();
$has_any_stations = false;
foreach($stations as $station) {
/** @var Entity\Station $station */
if ($this->acl->userAllowed($user, Acl::STATION_MEDIA, $station->getId())) {
$has_any_stations = true;
$station_media_dir = $station->getRadioMediaDir();
$symlink_path = $ftp_dir . '/' . $station->getShortName();
symlink($station_media_dir, $symlink_path);
}
}
if (!$has_any_stations) {
return $error;
}
return [
'auth_ok:1',
'uid:1000',
'gid:1000',
'dir:'.$ftp_dir.'/./',
'end',
];
}
/**
* @return array|null FTP connection information, if FTP is enabled.
*/
public function getInfo(): ?array
{
if (!$this->isEnabled()) {
return null;
}
$base_url = $this->router->getBaseUrl(false)
->withScheme('ftp')
->withPort(null);
$port = $_ENV['AZURACAST_FTP_PORT'] ?? 21;
return [
'url' => (string)$base_url,
'ip' => $this->ac_central->getIp(),
'port' => $port,
];
}
/**
* @return bool Whether FTP services are enabled for this installation.
*/
public function isEnabled(): bool
{
if (!$this->app_settings->isDocker() || $_ENV['AZURACAST_DC_REVISION'] < 6) {
return false;
}
return (bool)$this->settings_repo->getSetting(Entity\Settings::ENABLE_FTP_SERVER, true);
}
}

View File

@ -174,20 +174,36 @@ class Utilities
/**
* Recursively remove a directory and its contents.
*
* @param string $dir
* @param string $source
* @return bool
*/
public static function rmdirRecursive($dir): void
public static function rmdirRecursive(string $source): bool
{
if (is_dir($dir)) {
$files = array_diff(scandir($dir, \SCANDIR_SORT_NONE), ['.', '..']);
foreach ($files as $file) {
self::rmdirRecursive($dir . '/' . $file);
}
@rmdir($dir);
} else {
@unlink($dir);
if (empty($source) || !file_exists($source)) {
return true;
}
if (is_file($source) || is_link($source)) {
return @unlink($source);
}
$files = new \RecursiveIteratorIterator(
new \RecursiveDirectoryIterator($source, \RecursiveDirectoryIterator::SKIP_DOTS),
\RecursiveIteratorIterator::CHILD_FIRST
);
foreach($files as $fileinfo) {
/** @var \SplFileInfo $fileinfo */
if ('link' !== $fileinfo->getType() && $fileinfo->isDir()) {
if (!rmdir($fileinfo->getRealPath())) {
return false;
}
} else if (!unlink($fileinfo->getRealPath())) {
return false;
}
}
return rmdir($source);
}
/**

View File

@ -34,13 +34,18 @@ $assets
</div>
</div>
</div>
<?php if (APP_INSIDE_DOCKER): ?>
<?php if ($ftp_info): ?>
<div class="card-body alert-info d-flex align-items-center" role="alert">
<div class="flex-shrink-0 mr-2">
<i class="material-icons" aria-hidden="true">info</i>
</div>
<div class="flex-fill">
<p class="mb-0"><?=sprintf(__('You can also upload files in bulk via SFTP by <a href="%s" target="_blank">following these instructions</a>. Newly uploaded files will automatically be processed within a few minutes.'), 'https://www.azuracast.com/help/faq_docker.html#access-files-via-sftp') ?></p>
<p class="mb-0">
<?=__('You can also upload files in bulk via FTP.') ?><br>
<button type="button" class="btn btn-link p-0" data-toggle="modal" data-target="#ftpinfo">
<?=__('View connection instructions') ?>
</button>
</p>
</div>
</div>
<?php endif; ?>
@ -193,3 +198,70 @@ $assets
</form>
</div>
</div>
<?php if ($ftp_info): ?>
<div id="ftpinfo" class="modal" tabindex="-1" role="dialog">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title"><?=__('FTP Connection Information') ?></h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
</div>
<div class="modal-body">
<table class="table table-striped">
<colgroup>
<col width="40%">
<col width="60%">
</colgroup>
<tbody>
<tr>
<td>
<?=__('Server') ?>
</td>
<td>
<?=$ftp_info['url'] ?><br>
<small><?=__('You may need to connect directly via your IP address, which is <code>%s</code>.', $ftp_info['ip']) ?></small>
</td>
</tr>
<tr>
<td>
<?=__('Port') ?>
</td>
<td>
<?=$ftp_info['port'] ?>
</td>
</tr>
<tr>
<td>
<?=__('Protocol') ?>
</td>
<td>
<?=__('FTP with Explicit TLS (FTPS)') ?><br>
<small><?=__('Unencrypted FTP is also allowed, but not recommended.') ?></small>
</td>
</tr>
<tr>
<td>
<?=__('Username') ?>
</td>
<td>
<?=__('Your AzuraCast E-mail Address') ?>
</td>
</tr>
<tr>
<td>
<?=__('Password') ?>
</td>
<td>
<?=__('Your AzuraCast Password') ?>
</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
</div>
<?php endif; ?>