src/Module/Util/Ui.php
<?php
declare(strict_types=0);
/**
* vim:set softtabstop=4 shiftwidth=4 expandtab:
*
* LICENSE: GNU Affero General Public License, version 3 (AGPL-3.0-or-later)
* Copyright Ampache.org, 2001-2023
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
*/
namespace Ampache\Module\Util;
use Ampache\Config\ConfigContainerInterface;
use Ampache\Module\Api\Api;
use Ampache\Module\Playback\Localplay\LocalPlay;
use Ampache\Module\Playback\Localplay\LocalPlayTypeEnum;
use Ampache\Repository\MetadataFieldRepositoryInterface;
use Ampache\Repository\Model\Playlist;
use Ampache\Repository\Model\Plugin;
use Ampache\Repository\Model\Search;
use Ampache\Config\AmpConfig;
use Ampache\Module\System\Core;
use Ampache\Module\System\Dba;
use Ampache\Repository\Model\Preference;
/**
* A collection of methods related to the user interface
*/
class Ui implements UiInterface
{
private static $_ticker;
private static $_icon_cache;
private static $_image_cache;
private ConfigContainerInterface $configContainer;
public function __construct(
ConfigContainerInterface $configContainer
) {
$this->configContainer = $configContainer;
}
/**
* find_template
*
* Return the path to the template file wanted. The file can be overwritten
* by the theme if it's not a php file, or if it is and if option
* allow_php_themes is set to true.
* @param string $template
*/
public static function find_template($template, bool $extern = false): string
{
$path = AmpConfig::get('theme_path') . '/templates/' . $template;
$realpath = __DIR__ . '/../../../public/' . $path;
$extension = strtolower(pathinfo($path, PATHINFO_EXTENSION));
if (($extension != 'php' || AmpConfig::get('allow_php_themes')) && file_exists($realpath) && is_file($realpath)) {
return $path;
} else {
if ($extern === true) {
return '/templates/' . $template;
}
return __DIR__ . '/../../../public/templates/' . $template;
}
}
public function showObjectNotFound(): void
{
$this->showHeader();
echo T_('You have requested an object that does not exist');
$this->showQueryStats();
$this->showFooter();
}
/**
* Displays the default error page
*/
public function accessDenied(string $error = 'Access Denied'): void
{
// Clear any buffered crap
ob_end_clean();
header("HTTP/1.1 403 $error");
require_once self::find_template('show_denied.inc.php');
}
/**
* Displays an error page when you can't write the config
*/
public function permissionDenied(string $fileName): void
{
// Clear any buffered crap
ob_end_clean();
header("HTTP/1.1 403 Permission Denied");
require_once self::find_template('show_denied_permission.inc.php');
}
/**
* ajax_include
*
* Does some trickery with the output buffer to return the output of a
* template.
*/
public static function ajax_include(string $template): string
{
ob_start();
require self::find_template('') . $template;
$output = ob_get_contents();
ob_end_clean();
return $output ?: '';
}
/**
* check_iconv
*
* Checks to see whether iconv is available.
*/
public static function check_iconv(): bool
{
if (function_exists('iconv') && function_exists('iconv_substr')) {
return true;
}
return false;
}
/**
* check_ticker
*
* Stupid little cutesie thing to ratelimit output of long-running
* operations.
*/
public static function check_ticker(): bool
{
if (defined('SSE_OUTPUT') || defined('API')) {
return false;
}
if (!isset(self::$_ticker) || (time() > self::$_ticker + 1)) {
self::$_ticker = time();
return true;
}
return false;
}
/**
* clean_utf8
*
* Removes characters that aren't valid in XML
* (which is a subset of valid UTF-8, but close enough for our purposes.)
* See http://www.w3.org/TR/2006/REC-xml-20060816/#charsets
* @param string $string
*/
public static function clean_utf8($string): string
{
if ($string) {
$clean = preg_replace(
'/[^\x{9}\x{a}\x{d}\x{20}-\x{d7ff}\x{e000}-\x{fffd}\x{10000}-\x{10ffff}]|[\x{7f}-\x{84}\x{86}-\x{9f}\x{fdd0}-\x{fddf}\x{1fffe}-\x{1ffff}\x{2fffe}-\x{2ffff}\x{3fffe}-\x{3ffff}\x{4fffe}-\x{4ffff}\x{5fffe}-\x{5ffff}\x{6fffe}-\x{6ffff}\x{7fffe}-\x{7ffff}\x{8fffe}-\x{8ffff}\x{9fffe}-\x{9ffff}\x{afffe}-\x{affff}\x{bfffe}-\x{bffff}\x{cfffe}-\x{cffff}\x{dfffe}-\x{dffff}\x{efffe}-\x{effff}\x{ffffe}-\x{fffff}\x{10fffe}-\x{10ffff}]/u',
'',
$string
);
if ($clean) {
return rtrim((string)$clean);
}
debug_event(self::class, 'Charset cleanup failed, something might break', 1);
}
return '';
}
/**
* format_bytes
*
* Turns a size in bytes into the best human-readable value
* @param $value
* @param int $precision
* @param int $pass
*/
public static function format_bytes($value, $precision = 2, $pass = 0): string
{
if (!$value) {
return '';
}
while (strlen((string)floor($value)) > 3) {
$value /= 1024;
$pass++;
}
switch ($pass) {
case 1:
$unit = 'kB';
break;
case 2:
$unit = 'MB';
break;
case 3:
$unit = 'GB';
break;
case 4:
$unit = 'TB';
break;
case 5:
$unit = 'PB';
break;
default:
$unit = 'B';
break;
}
return ((string)round($value, $precision)) . ' ' . $unit;
}
/**
* unformat_bytes
*
* Parses a human-readable size
* @param string|int $value
* @return string
* @noinspection PhpMissingBreakStatementInspection
*/
public static function unformat_bytes($value): string
{
if (preg_match('/^([0-9]+) *([[:alpha:]]+)$/', (string)$value, $matches)) {
$value = (int)$matches[1];
$unit = strtolower(substr($matches[2], 0, 1));
} else {
return (string)$value;
}
switch ($unit) {
case 'p':
$value *= 1024;
// Intentional break fall-through
case 't':
$value *= 1024;
// Intentional break fall-through
case 'g':
$value *= 1024;
// Intentional break fall-through
case 'm':
$value *= 1024;
// Intentional break fall-through
case 'k':
$value *= 1024;
// Intentional break fall-through
}
return (string)$value;
}
/**
* get_icon
*
* Returns an <img> or <svg> tag for the specified icon
*/
public static function get_icon(string $name, ?string $title = null, ?string $id_attrib = null, ?string $class_attrib = null): string
{
$title = $title ?? T_(ucfirst($name));
$icon_url = self::_find_icon($name);
$icontype = pathinfo($icon_url, PATHINFO_EXTENSION);
$tag = '';
if ($icontype == 'svg') {
// load svg file
$svgicon = simplexml_load_file($icon_url);
if ($svgicon !== false) {
if (empty($svgicon->title)) {
$svgicon->addChild('title', $title);
} else {
$svgicon->title = $title;
}
if (empty($svgicon->desc)) {
$svgicon->addChild('desc', $title);
} else {
$svgicon->desc = $title;
}
if (!empty($id_attrib)) {
$svgicon->addAttribute('id', $id_attrib);
}
if (empty($class_attrib)) {
$class_attrib = 'icon icon-' . $name;
}
$svgicon->addAttribute('class', $class_attrib);
$tag = explode("\n", (string)$svgicon->asXML(), 2)[1];
}
} else {
// fall back to png
$tag = '<img src="' . $icon_url . '" ';
$tag .= 'alt="' . $title . '" ';
$tag .= 'title="' . $title . '" ';
if ($id_attrib !== null) {
$tag .= 'id="' . $id_attrib . '" ';
}
if ($class_attrib !== null) {
$tag .= 'class="' . $class_attrib . '" ';
}
$tag .= '/>';
}
return $tag;
}
/**
* _find_icon
*
* Does the finding icon thing. match svg first over png
* @param string $name
*/
private static function _find_icon($name): string
{
if (isset(self::$_icon_cache[$name])) {
return self::$_icon_cache[$name];
}
$path = AmpConfig::get('theme_path') . '/images/icons/';
$filesearch = glob(__DIR__ . '/../../../public/' . $path . 'icon_' . $name . '.{svg,png}', GLOB_BRACE);
if (empty($filesearch)) {
// if the theme is missing an icon. fall back to default images folder
$filename = 'icon_' . $name . '.png';
$path = '/images/';
} else {
$filename = pathinfo($filesearch[0], PATHINFO_BASENAME);
}
$url = AmpConfig::get('web_path') . $path . $filename;
// cache the url so you don't need to keep searching
self::$_icon_cache[$name] = $url;
return $url;
}
/**
* get_image
*
* Returns an <img> or <svg> tag for the specified image
*/
public static function get_image(string $name, ?string $title = null, ?string $id_attrib = null, ?string $class_attrib = null): string
{
$title = $title ?? ucfirst($name);
$image_url = self::_find_image($name);
$imagetype = pathinfo($image_url, PATHINFO_EXTENSION);
$tag = '';
if ($imagetype == 'svg') {
// load svg file
$svgimage = simplexml_load_file($image_url);
if ($svgimage !== false) {
$svgimage->addAttribute('class', 'image');
if (empty($svgimage->title)) {
$svgimage->addChild('title', $title);
} else {
$svgimage->title = $title;
}
if (empty($svgimage->desc)) {
$svgimage->addChild('desc', $title);
} else {
$svgimage->desc = $title;
}
if (!empty($id_attrib)) {
$svgimage->addAttribute('id', $id_attrib);
}
$class_attrib = ($class_attrib) ?? 'image image-' . $name;
$svgimage->addAttribute('class', $class_attrib);
$tag = explode("\n", (string)$svgimage->asXML(), 2)[1];
}
} else {
// fall back to png
$tag = '<img src="' . $image_url . '" ';
$tag .= 'alt="' . $title . '" ';
$tag .= 'title="' . $title . '" ';
if ($id_attrib !== null) {
$tag .= 'id="' . $id_attrib . '" ';
}
if ($class_attrib !== null) {
$tag .= 'class="' . $class_attrib . '" ';
}
$tag .= '/>';
}
return $tag;
}
/**
* _find_image
*
* Does the finding image thing. match svg first over png
* @param string $name
*/
private static function _find_image($name): string
{
if (isset(self::$_image_cache[$name])) {
return self::$_image_cache[$name];
}
$path = AmpConfig::get('theme_path') . '/images/';
$filesearch = glob(__DIR__ . '/../../../public/' . $path . $name . '.{svg,png}', GLOB_BRACE);
if (empty($filesearch)) {
// if the theme is missing an image. fall back to default images folder
$filename = $name . '.png';
$path = '/images/';
} else {
$filename = pathinfo($filesearch[0], PATHINFO_BASENAME);
}
$url = AmpConfig::get('web_path') . $path . $filename;
// cache the url so you don't need to keep searching
self::$_image_cache[$name] = $url;
return $url;
}
/**
* Show the requested template file
*/
public function show(string $template, array $context = []): void
{
extract($context);
require_once self::find_template($template);
}
public function showFooter(): void
{
static::show_footer();
}
public function showHeader(): void
{
require_once self::find_template('header.inc.php');
}
/**
* show_footer
*
* Shows the footer template and possibly profiling info.
*
* @deprecated use non-static version
*/
public static function show_footer(): void
{
if (!defined("TABLE_RENDERED")) {
show_table_render();
}
$plugins = Plugin::get_plugins('display_on_footer');
foreach ($plugins as $plugin_name) {
$plugin = new Plugin($plugin_name);
if ($plugin->_plugin !== null && $plugin->load(Core::get_global('user'))) {
$plugin->_plugin->display_on_footer();
}
}
require_once self::find_template('footer.inc.php');
if (Core::get_request('profiling') !== '') {
Dba::show_profile();
}
}
public function showBoxTop(string $title = '', string $class = ''): void
{
static::show_box_top($title, $class);
}
public function showBoxBottom(): void
{
static::show_box_bottom();
}
/**
* show_box_top
*
* This shows the top of the box.
* @param string $title
* @param string $class
*
* @deprecated Use non-static version
*/
public static function show_box_top($title = '', $class = ''): void
{
require self::find_template('show_box_top.inc.php');
}
/**
* show_box_bottom
*
* This shows the bottom of the box
*
* @deprecated Use non-static version
*/
public static function show_box_bottom(): void
{
require self::find_template('show_box_bottom.inc.php');
}
/**
* This shows the query stats
*/
public function showQueryStats(): void
{
require self::find_template('show_query_stats.inc.php');
}
public static function show_custom_style(): void
{
if (AmpConfig::get('custom_login_background', false)) {
echo "<style> body { background-position: center; background-size: cover; background-image: url('" . AmpConfig::get('custom_login_background') . "') !important; }</style>";
}
if (AmpConfig::get('custom_login_logo', false)) {
echo "<style>#loginPage #headerlogo, #registerPage #headerlogo { background-image: url('" . AmpConfig::get('custom_login_logo') . "') !important; }</style>";
}
$favicon = AmpConfig::get('custom_favicon', false) ?: AmpConfig::get('web_path') . "/favicon.ico";
echo "<link rel='shortcut icon' href='" . $favicon . "' />\n";
}
/**
* update_text
*
* Convenience function that, if the output is going to a browser,
* blarfs JS to do a fancy update. Otherwise it just outputs the text.
* @param string $field
* @param $value
*/
public static function update_text($field, $value): void
{
if (defined('API')) {
return;
}
if (defined('CLI')) {
echo $value . "\n";
return;
}
static $update_id = 1;
if (defined('SSE_OUTPUT')) {
echo "id: " . $update_id . "\n";
echo "data: displayNotification('" . json_encode($value) . "', 5000)\n\n";
} else {
if (!empty($field)) {
echo "<script>updateText('" . $field . "', '" . json_encode($value) . "');</script>\n";
} else {
echo "<br />" . $value . "<br /><br />\n";
}
}
ob_flush();
flush();
$update_id++;
}
/**
* get_logo_url
*
* Get the custom logo or logo relating to your theme color
* @param string $color
*/
public static function get_logo_url($color = null): string
{
if (AmpConfig::get('custom_logo')) {
return AmpConfig::get('custom_logo');
}
if ($color !== null) {
return AmpConfig::get('web_path') . AmpConfig::get('theme_path') . '/images/ampache-' . $color . '.png';
}
return AmpConfig::get('web_path') . AmpConfig::get('theme_path') . '/images/ampache-' . AmpConfig::get('theme_color') . '.png';
}
/**
* @param $type
*/
public static function is_grid_view($type): bool
{
$isgv = true;
$name = 'browse_' . $type . '_grid_view';
if (isset($_COOKIE[$name])) {
$isgv = ($_COOKIE[$name] == 'true');
}
return $isgv;
}
/**
* shows a confirmation of an action
*
* @param string $title The Title of the message
* @param string $text The details of the message
* @param string $next_url Where to go next
* @param int $cancel T/F show a cancel button that uses return_referer()
* @param string $form_name
* @param bool $visible
*/
public function showConfirmation(
$title,
$text,
$next_url,
$cancel = 0,
$form_name = 'confirmation',
$visible = true
): void {
$webPath = $this->configContainer->getWebPath();
if (substr_count($next_url, $webPath)) {
$path = $next_url;
} else {
$path = sprintf('%s/%s', $webPath, $next_url);
}
$this->show(
'show_confirmation.inc.php',
[
'title' => $title,
'text' => $text,
'path' => $path,
'form_name' => $form_name,
'cancel' => $cancel
]
);
}
/**
* shows a simple continue button after an action
*/
public function showContinue(
string $title,
string $text,
string $next_url
): void {
$webPath = $this->configContainer->getWebPath();
if (substr_count($next_url, $webPath)) {
$path = $next_url;
} else {
$path = sprintf('%s/%s', $webPath, $next_url);
}
$this->show(
'show_continue.inc.php',
[
'title' => $title,
'text' => $text,
'path' => $path
]
);
}
/**
* This function is used to escape user data that is getting redisplayed
* onto the page, it htmlentities the mojo
* This is the inverse of the scrub_in function
*/
public function scrubOut(?string $string): string
{
if ($string === null) {
return '';
}
return htmlentities((string) $string, ENT_QUOTES, AmpConfig::get('site_charset'));
}
/**
* takes the key and then creates the correct type of input for updating it
*/
public function createPreferenceInput(
string $name,
$value
): void {
if (!Preference::has_access($name)) {
if ($value == '1') {
echo T_("Enabled");
} elseif ($value == '0') {
echo T_("Disabled");
} else {
if (preg_match('/_pass$/', $name) || preg_match('/_api_key$/', $name)) {
echo "******";
} else {
echo $value;
}
}
return;
} // if we don't have access to it
switch ($name) {
case 'access_control':
case 'access_list':
case 'ajax_load':
case 'album_group':
case 'album_release_type':
case 'allow_democratic_playback':
case 'allow_localplay_playback':
case 'allow_personal_info_agent':
case 'allow_personal_info_now':
case 'allow_personal_info_recent':
case 'allow_personal_info_time':
case 'allow_stream_playback':
case 'allow_upload':
case 'allow_video':
case 'api_enable_3':
case 'api_enable_4':
case 'api_enable_5':
case 'api_enable_6':
case 'api_hide_dupe_searches':
case 'autoupdate':
case 'autoupdate_lastversion_new':
case 'bookmark_latest':
case 'broadcast_by_default':
case 'browse_filter':
case 'browser_notify':
case 'catalog_check_duplicate':
case 'catalogfav_gridview':
case 'condPL':
case 'cron_cache':
case 'daap_backend':
case 'demo_clear_sessions':
case 'demo_mode':
case 'demo_use_search':
case 'direct_link':
case 'display_menu':
case 'download':
case 'force_http_play':
case 'geolocation':
case 'hide_genres':
case 'hide_single_artist':
case 'home_moment_albums':
case 'home_moment_videos':
case 'home_now_playing':
case 'home_recently_played':
case 'home_recently_played_all':
case 'libitem_contextmenu':
case 'lock_songs':
case 'mb_overwrite_name':
case 'no_symlinks':
case 'notify_email':
case 'now_playing_per_user':
case 'perpetual_api_session':
case 'personalfav_display':
case 'quarantine':
case 'ratingmatch_flags':
case 'ratingmatch_write_tags':
case 'rio_global_stats':
case 'rio_track_stats':
case 'share':
case 'share_social':
case 'show_album_artist':
case 'show_artist':
case 'show_donate':
case 'show_header_login':
case 'show_license':
case 'show_lyrics':
case 'show_original_year':
case 'show_played_times':
case 'show_playlist_username':
case 'show_skipped_times':
case 'show_wrapped':
case 'show_subtitle':
case 'sidebar_light':
case 'song_page_title':
case 'stream_beautiful_url':
case 'subsonic_always_download':
case 'subsonic_backend':
case 'tadb_overwrite_name':
case 'topmenu':
case 'ui_fixed':
case 'unique_playlist':
case 'upload':
case 'upload_allow_edit':
case 'upload_allow_remove':
case 'upload_catalog_pattern':
case 'upload_subdir':
case 'upload_user_artist':
case 'upnp_backend':
case 'use_auth':
case 'use_original_year':
case 'use_play2':
case 'webdav_backend':
case 'webplayer_aurora':
case 'webplayer_confirmclose':
case 'webplayer_flash':
case 'webplayer_html5':
case 'webplayer_pausetabs':
case 'xml_rpc':
$is_true = '';
$is_false = '';
if ($value == '1') {
$is_true = "selected=\"selected\"";
} else {
$is_false = "selected=\"selected\"";
}
echo "<select name=\"$name\">\n";
echo "\t<option value=\"1\" $is_true>" . T_('On') . "</option>\n";
echo "\t<option value=\"0\" $is_false>" . T_('Off') . "</option>\n";
echo "</select>\n";
break;
case 'upload_catalog':
show_catalog_select('upload_catalog', $value, '', true, 'music');
break;
case 'play_type':
$is_stream = '';
$is_localplay = '';
$is_democratic = '';
$is_web_player = '';
switch ($value) {
case 'localplay':
$is_localplay = 'selected="selected"';
break;
case 'democratic':
$is_democratic = 'selected="selected"';
break;
case 'web_player':
$is_web_player = 'selected="selected"';
break;
default:
$is_stream = 'selected="selected"';
}
echo "<select name=\"$name\">\n";
echo "\t<option value=\"\">" . T_('None') . "</option>\n";
if (AmpConfig::get('allow_stream_playback')) {
echo "\t<option value=\"stream\" $is_stream>" . T_('Stream') . "</option>\n";
}
if (AmpConfig::get('allow_democratic_playback')) {
echo "\t<option value=\"democratic\" $is_democratic>" . T_('Democratic') . "</option>\n";
}
if (AmpConfig::get('allow_localplay_playback')) {
echo "\t<option value=\"localplay\" $is_localplay>" . T_('Localplay') . "</option>\n";
}
echo "\t<option value=\"web_player\" $is_web_player>" . T_('Web Player') . "</option>\n";
echo "</select>\n";
break;
case 'playlist_type':
$is_m3u = '';
$is_simple_m3u = '';
$is_pls = '';
$is_asx = '';
$is_ram = '';
$is_xspf = '';
switch ($value) {
case 'simple_m3u':
$is_simple_m3u = 'selected="selected"';
break;
case 'pls':
$is_pls = 'selected="selected"';
break;
case 'asx':
$is_asx = 'selected="selected"';
break;
case 'ram':
$is_ram = 'selected="selected"';
break;
case 'xspf':
$is_xspf = 'selected="selected"';
break;
case 'm3u':
default:
$is_m3u = 'selected="selected"';
}
echo "<select name=\"$name\">\n";
echo "\t<option value=\"m3u\" $is_m3u>" . T_('M3U') . "</option>\n";
echo "\t<option value=\"simple_m3u\" $is_simple_m3u>" . T_('Simple M3U') . "</option>\n";
echo "\t<option value=\"pls\" $is_pls>" . T_('PLS') . "</option>\n";
echo "\t<option value=\"asx\" $is_asx>" . T_('Asx') . "</option>\n";
echo "\t<option value=\"ram\" $is_ram>" . T_('RAM') . "</option>\n";
echo "\t<option value=\"xspf\" $is_xspf>" . T_('XSPF') . "</option>\n";
echo "</select>\n";
break;
case 'lang':
$languages = get_languages();
echo '<select name="' . $name . '">' . "\n";
foreach ($languages as $lang => $tongue) {
$selected = ($lang == $value) ? 'selected="selected"' : '';
echo "\t<option value=\"$lang\" " . $selected . ">$tongue</option>\n";
} // end foreach
echo "</select>\n";
break;
case 'localplay_controller':
$controllers = array_keys(LocalPlayTypeEnum::TYPE_MAPPING);
echo "<select name=\"$name\">\n";
echo "\t<option value=\"\">" . T_('None') . "</option>\n";
foreach ($controllers as $controller) {
if (!LocalPlay::is_enabled($controller)) {
continue;
}
$is_selected = '';
if ($value == $controller) {
$is_selected = 'selected="selected"';
}
echo "\t<option value=\"" . $controller . "\" $is_selected>" . ucfirst($controller) . "</option>\n";
} // end foreach
echo "</select>\n";
break;
case 'api_force_version':
$is_0 = '';
$is_3 = '';
$is_4 = '';
$is_5 = '';
$is_6 = '';
if (!in_array($value, Api::API_VERSIONS)) {
$is_0 = 'selected="selected"';
} elseif ($value == 3) {
$is_3 = 'selected="selected"';
} elseif ($value == 4) {
$is_4 = 'selected="selected"';
} elseif ($value == 5) {
$is_5 = 'selected="selected"';
} elseif ($value == 6) {
$is_6 = 'selected="selected"';
}
echo "<select name=\"$name\">\n";
echo "<option value=\"0\" $is_0>" . T_('Off') . "</option>\n";
echo "<option value=\"3\" $is_3>" . T_('Allow API3 Only') . "</option>\n";
echo "<option value=\"4\" $is_4>" . T_('Allow API4 Only') . "</option>\n";
echo "<option value=\"5\" $is_5>" . T_('Allow API5 Only') . "</option>\n";
echo "<option value=\"6\" $is_6>" . T_('Allow API6 Only') . "</option>\n";
echo "</select>\n";
break;
case 'jp_volume':
$is_0 = '';
$is_1 = '';
$is_2 = '';
$is_3 = '';
$is_4 = '';
$is_5 = '';
$is_6 = '';
$is_7 = '';
$is_8 = '';
$is_9 = '';
$is_10 = '';
if ($value == 0.0) {
$is_0 = 'selected="selected"';
} elseif ($value == 0.1) {
$is_1 = 'selected="selected"';
} elseif ($value == 0.2) {
$is_2 = 'selected="selected"';
} elseif ($value == 0.3) {
$is_3 = 'selected="selected"';
} elseif ($value == 0.4) {
$is_4 = 'selected="selected"';
} elseif ($value == 0.5) {
$is_5 = 'selected="selected"';
} elseif ($value == 0.6) {
$is_6 = 'selected="selected"';
} elseif ($value == 0.7) {
$is_7 = 'selected="selected"';
} elseif ($value == 0.8) {
$is_8 = 'selected="selected"';
} elseif ($value == 0.9) {
$is_9 = 'selected="selected"';
} elseif ($value == 1.0) {
$is_10 = 'selected="selected"';
}
echo "<select name=\"$name\">\n";
echo "<option value=0.00 $is_0>0%</option>\n";
echo "<option value=0.10 $is_1>10%</option>\n";
echo "<option value=0.20 $is_2>20%</option>\n";
echo "<option value=0.30 $is_3>30%</option>\n";
echo "<option value=0.40 $is_4>40%</option>\n";
echo "<option value=0.50 $is_5>50%</option>\n";
echo "<option value=0.60 $is_6>60%</option>\n";
echo "<option value=0.70 $is_7>70%</option>\n";
echo "<option value=0.80 $is_8>80%</option>\n";
echo "<option value=0.90 $is_9>90%</option>\n";
echo "<option value=1.00 $is_10>100%</option>\n";
echo "</select>\n";
break;
case 'ratingmatch_stars':
$is_0 = '';
$is_1 = '';
$is_2 = '';
$is_3 = '';
$is_4 = '';
$is_5 = '';
if ($value == 0) {
$is_0 = 'selected="selected"';
} elseif ($value == 1) {
$is_1 = 'selected="selected"';
} elseif ($value == 2) {
$is_2 = 'selected="selected"';
} elseif ($value == 3) {
$is_3 = 'selected="selected"';
} elseif ($value == 4) {
$is_4 = 'selected="selected"';
} elseif ($value == 5) {
$is_5 = 'selected="selected"';
}
echo "<select name=\"$name\">\n";
echo "<option value=\"0\" $is_0>" . T_('Disabled') . "</option>\n";
echo "<option value=\"1\" $is_1>" . T_('1 Star') . "</option>\n";
echo "<option value=\"2\" $is_2>" . T_('2 Stars') . "</option>\n";
echo "<option value=\"3\" $is_3>" . T_('3 Stars') . "</option>\n";
echo "<option value=\"4\" $is_4>" . T_('4 Stars') . "</option>\n";
echo "<option value=\"5\" $is_5>" . T_('5 Stars') . "</option>\n";
echo "</select>\n";
break;
case 'localplay_level':
case 'upload_access_level':
$is_user = '';
$is_content_manager = '';
$is_catalog_manager = '';
$is_admin = '';
if ($value == '25') {
$is_user = 'selected="selected"';
} elseif ($value == '50') {
$is_content_manager = 'selected="selected"';
} elseif ($value == '75') {
$is_catalog_manager = 'selected="selected"';
} elseif ($value == '100') {
$is_admin = 'selected="selected"';
}
echo "<select name=\"$name\">\n";
echo "<option value=\"0\">" . T_('Disabled') . "</option>\n";
echo "<option value=\"25\" $is_user>" . T_('User') . "</option>\n";
echo "<option value=\"50\" $is_content_manager>" . T_('Content Manager') . "</option>\n";
echo "<option value=\"75\" $is_catalog_manager>" . T_('Catalog Manager') . "</option>\n";
echo "<option value=\"100\" $is_admin>" . T_('Admin') . "</option>\n";
echo "</select>\n";
break;
case 'webplayer_removeplayed':
$is_one = '';
$is_two = '';
$is_three = '';
$is_five = '';
$is_ten = '';
$is_all = '';
if ($value == '1') {
$is_one = 'selected="selected"';
} elseif ($value == '2') {
$is_two = 'selected="selected"';
} elseif ($value == '3') {
$is_three = 'selected="selected"';
} elseif ($value == '5') {
$is_five = 'selected="selected"';
} elseif ($value == '10') {
$is_ten = 'selected="selected"';
} elseif ($value == '999') {
$is_all = 'selected="selected"';
}
echo "<select name=\"$name\">\n";
echo "<option value=\"0\">" . T_('Disabled') . "</option>\n";
echo "<option value=\"1\" $is_one>" . T_('Keep last played track') . "</option>\n";
/* HINT: Keep (2|3|4|5|10) previous tracks */
echo "<option value=\"2\" $is_two>" . sprintf(T_('Keep %s previous tracks'), '2') . "</option>\n";
echo "<option value=\"3\" $is_three>" . sprintf(T_('Keep %s previous tracks'), '3') . "</option>\n";
echo "<option value=\"5\" $is_five>" . sprintf(T_('Keep %s previous tracks'), '5') . "</option>\n";
echo "<option value=\"10\" $is_ten>" . sprintf(T_('Keep %s previous tracks'), '10') . "</option>\n";
echo "<option value=\"999\" $is_all>" . T_('Remove all previous tracks') . "</option>\n";
echo "</select>\n";
break;
case 'theme_name':
$themes = get_themes();
echo "<select name=\"$name\">\n";
foreach ($themes as $theme) {
$is_selected = "";
if ($value == $theme['path']) {
$is_selected = "selected=\"selected\"";
}
echo "\t<option value=\"" . $theme['path'] . "\" $is_selected>" . $theme['name'] . "</option>\n";
} // foreach themes
echo "</select>\n";
break;
case 'theme_color':
// This include a two-step configuration (first change theme and save, then change theme color and save)
$theme_cfg = get_theme(AmpConfig::get('theme_name'));
if ($theme_cfg !== null) {
echo "<select name=\"$name\">\n";
foreach ($theme_cfg['colors'] as $color) {
$is_selected = "";
if ($value == strtolower((string) $color)) {
$is_selected = "selected=\"selected\"";
}
echo "\t<option value=\"" . strtolower((string) $color) . "\" $is_selected>" . $color . "</option>\n";
} // foreach themes
echo "</select>\n";
}
break;
case 'playlist_method':
$is_send = '';
$is_send_clear = '';
$is_clear = '';
$is_default = '';
if ($value == 'send') {
$is_send = 'selected="selected"';
} elseif ($value == 'send_clear') {
$is_send_clear = 'selected="selected"';
} elseif ($value == 'clear') {
$is_clear = 'selected="selected"';
} elseif ($value == 'default') {
$is_default = 'selected="selected"';
}
echo "<select name=\"$name\">\n";
echo "\t<option value=\"send\"$is_send>" . T_('Send on Add') . "</option>\n";
echo "\t<option value=\"send_clear\"$is_send_clear>" . T_('Send and Clear on Add') . "</option>\n";
echo "\t<option value=\"clear\"$is_clear>" . T_('Clear on Send') . "</option>\n";
echo "\t<option value=\"default\"$is_default>" . T_('Default') . "</option>\n";
echo "</select>\n";
break;
case 'transcode':
$is_never = '';
$is_default = '';
$is_always = '';
if ($value == 'never') {
$is_never = 'selected="selected"';
} elseif ($value == 'default') {
$is_default = 'selected="selected"';
} elseif ($value == 'always') {
$is_always = 'selected="selected"';
}
echo "<select name=\"$name\">\n";
echo "\t<option value=\"never\"$is_never>" . T_('Never') . "</option>\n";
echo "\t<option value=\"default\"$is_default>" . T_('Default') . "</option>\n";
echo "\t<option value=\"always\"$is_always>" . T_('Always') . "</option>\n";
echo "</select>\n";
break;
case 'album_sort':
$is_sort_year_asc = '';
$is_sort_year_desc = '';
$is_sort_name_asc = '';
$is_sort_name_desc = '';
$is_sort_default = '';
if ($value == 'year_asc') {
$is_sort_year_asc = 'selected="selected"';
} elseif ($value == 'year_desc') {
$is_sort_year_desc = 'selected="selected"';
} elseif ($value == 'name_asc') {
$is_sort_name_asc = 'selected="selected"';
} elseif ($value == 'name_desc') {
$is_sort_name_desc = 'selected="selected"';
} else {
$is_sort_default = 'selected="selected"';
}
echo "<select name=\"$name\">\n";
echo "\t<option value=\"default\" $is_sort_default>" . T_('Default') . "</option>\n";
echo "\t<option value=\"year_asc\" $is_sort_year_asc>" . T_('Year ascending') . "</option>\n";
echo "\t<option value=\"year_desc\" $is_sort_year_desc>" . T_('Year descending') . "</option>\n";
echo "\t<option value=\"name_asc\" $is_sort_name_asc>" . T_('Name ascending') . "</option>\n";
echo "\t<option value=\"name_desc\" $is_sort_name_desc>" . T_('Name descending') . "</option>\n";
echo "</select>\n";
break;
case 'disabled_custom_metadata_fields':
$ids = explode(',', $value);
$options = array();
foreach ($this->getMetadataFieldRepository()->getPropertyList() as $propertyId => $propertyName) {
$selected = in_array($propertyId, $ids) ? ' selected="selected"' : '';
$options[] = '<option value="' . $propertyId . '"' . $selected . '>' . $propertyName . '</option>';
}
echo '<select multiple size="5" name="' . $name . '[]">' . implode("\n", $options) . '</select>';
break;
case 'personalfav_playlist':
case 'personalfav_smartlist':
$ids = explode(',', $value);
$options = array();
$playlists = ($name == 'personalfav_smartlist') ? Search::get_search_array() : Playlist::get_playlist_array();
if (!empty($playlists)) {
foreach ($playlists as $list_id => $list_name) {
$selected = in_array($list_id, $ids) ? ' selected="selected"' : '';
$options[] = '<option value="' . $list_id . '"' . $selected . '>' . scrub_out($list_name) . '</option>';
}
echo '<select multiple size="5" name="' . $name . '[]">' . implode("\n", $options) . '</select>';
}
break;
case 'lastfm_grant_link':
case 'librefm_grant_link':
// construct links for granting access Ampache application to Last.fm and Libre.fm
$plugin_name = ucfirst(str_replace('_grant_link', '', $name));
$plugin = new Plugin($plugin_name);
$url = $plugin->_plugin->url;
$api_key = rawurlencode(AmpConfig::get('lastfm_api_key'));
$callback = rawurlencode(AmpConfig::get('web_path') . '/preferences.php?tab=plugins&action=grant&plugin=' . $plugin_name);
/* HINT: Plugin Name */
echo "<a href=\"$url/api/auth/?api_key=$api_key&cb=$callback\" target=\"_blank\">" . Ui::get_icon('plugin', sprintf(T_("Click to grant %s access to Ampache"), $plugin_name)) . '</a>';
break;
default:
if (preg_match('/_pass$/', $name)) {
echo '<input type="password" name="' . $name . '" value="******" />';
} else {
echo '<input type="text" name="' . $name . '" value="' . strip_tags($value) . '" />';
}
break;
}
}
/**
* This shows the preference box for the preferences pages.
*
* @var array<string, mixed> $preferences
*/
public function showPreferenceBox(array $preferences): void
{
$this->show(
'show_preference_box.inc.php',
[
'preferences' => $preferences,
'ui' => $this
]
);
}
/**
* This function takes a boolean value and then prints out a friendly text
* message.
*/
public static function printBool(bool $value): string
{
if ($value) {
$string = '<span class="item_on">' . T_('On') . '</span>';
} else {
$string = '<span class="item_off">' . T_('Off') . '</span>';
}
return $string;
}
/**
* @todo inject dependency
*/
private function getMetadataFieldRepository(): MetadataFieldRepositoryInterface
{
global $dic;
return $dic->get(MetadataFieldRepositoryInterface::class);
}
}