feat(vip): add default icons and remove download speed

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
2026-08-11 17:48:10 +08:00
co-authored by Claude Fable 5
parent 77d54b3b9d
commit 18da39788f
15 changed files with 105 additions and 74 deletions
+2 -5
View File
@@ -112,12 +112,12 @@ class SchemaPayment {
['key' => 'pay_user_vip_1_name', 'label' => '一级会员名称', 'type' => 'input', 'default' => '一级会员', 'dependsOn' => ['key' => 'pay_user_vip_1_s', 'value' => true]],
['key' => 'pay_user_vip_1_desc', 'label' => '一级会员一句话简介', 'type' => 'input', 'default' => '尊享一级会员特权', 'dependsOn' => ['key' => 'pay_user_vip_1_s', 'value' => true]],
['key' => 'pay_user_vip_1_equity', 'label' => '一级会员权益 HTML', 'type' => 'textarea', 'default' => '<li>免费下载部分资源</li><li>会员专属身份标识</li><li>付费内容会员价</li>', 'dependsOn' => ['key' => 'pay_user_vip_1_s', 'value' => true]],
['key' => 'vip_1_img_icon', 'label' => '一级会员图标 URL', 'type' => 'input', 'default' => '', 'dependsOn' => ['key' => 'pay_user_vip_1_s', 'value' => true]],
['key' => 'vip_1_img_icon', 'label' => '一级会员图标 URL', 'type' => 'input', 'default' => '', 'dependsOn' => ['key' => 'pay_user_vip_1_s', 'value' => true], 'help' => '留空使用内置 vip-1.svg 图标'],
['key' => 'pay_user_vip_2_s', 'label' => '启用二级会员', 'type' => 'switch', 'default' => true],
['key' => 'pay_user_vip_2_name', 'label' => '二级会员名称', 'type' => 'input', 'default' => '二级会员', 'dependsOn' => ['key' => 'pay_user_vip_2_s', 'value' => true]],
['key' => 'pay_user_vip_2_desc', 'label' => '二级会员一句话简介', 'type' => 'input', 'default' => '尊享二级会员特权', 'dependsOn' => ['key' => 'pay_user_vip_2_s', 'value' => true]],
['key' => 'pay_user_vip_2_equity', 'label' => '二级会员权益 HTML', 'type' => 'textarea', 'default' => '<li>更高免费下载额度</li><li>更高等级身份标识</li><li>更多付费内容会员价</li>', 'dependsOn' => ['key' => 'pay_user_vip_2_s', 'value' => true]],
['key' => 'vip_2_img_icon', 'label' => '二级会员图标 URL', 'type' => 'input', 'default' => '', 'dependsOn' => ['key' => 'pay_user_vip_2_s', 'value' => true]],
['key' => 'vip_2_img_icon', 'label' => '二级会员图标 URL', 'type' => 'input', 'default' => '', 'dependsOn' => ['key' => 'pay_user_vip_2_s', 'value' => true], 'help' => '留空使用内置 vip-2.svg 图标'],
['key' => 'pay_user_vip_desc', 'label' => '弹窗顶部会员说明', 'type' => 'textarea', 'default' => ''],
['key' => 'pay_user_vip_more', 'label' => '弹窗底部补充说明 HTML', 'type' => 'textarea', 'default' => ''],
]],
@@ -134,11 +134,8 @@ class SchemaPayment {
]],
['key' => 'benefit', 'title' => '下载权益', 'fields' => [
['key' => 'pay_download_limit', 'label' => '普通用户下载限制', 'type' => 'number', 'default' => 0, 'min' => 0, 'max' => 9999],
['key' => 'pay_download_speed', 'label' => '普通用户下载速度(KB/s)', 'type' => 'number', 'default' => 0, 'min' => 0, 'max' => 99999],
['key' => 'pay_download_limit_vip_1', 'label' => '一级会员下载限制', 'type' => 'number', 'default' => 0, 'min' => 0, 'max' => 9999, 'dependsOn' => ['key' => 'pay_user_vip_1_s', 'value' => true]],
['key' => 'pay_download_speed_vip_1', 'label' => '一级会员下载速度(KB/s)', 'type' => 'number', 'default' => 0, 'min' => 0, 'max' => 99999, 'dependsOn' => ['key' => 'pay_user_vip_1_s', 'value' => true]],
['key' => 'pay_download_limit_vip_2', 'label' => '二级会员下载限制', 'type' => 'number', 'default' => 0, 'min' => 0, 'max' => 9999, 'dependsOn' => ['key' => 'pay_user_vip_2_s', 'value' => true]],
['key' => 'pay_download_speed_vip_2', 'label' => '二级会员下载速度(KB/s)', 'type' => 'number', 'default' => 0, 'min' => 0, 'max' => 99999, 'dependsOn' => ['key' => 'pay_user_vip_2_s', 'value' => true]],
['key' => 'pay_vip_pass_charge_s', 'label' => '会员卡密兑换', 'type' => 'switch', 'default' => false],
['key' => 'pay_vip_pass_charge_desc', 'label' => '卡密兑换说明', 'type' => 'textarea', 'default' => '', 'dependsOn' => ['key' => 'pay_vip_pass_charge_s', 'value' => true]],
['key' => 'pay_vip_pass_charge_only_password', 'label' => '仅密码兑换', 'type' => 'switch', 'default' => true, 'dependsOn' => ['key' => 'pay_vip_pass_charge_s', 'value' => true]],
-1
View File
@@ -127,7 +127,6 @@ class SchemaPermissions {
['key' => 'download_credits_cost', 'label' => '默认积分价参考', 'type' => 'number', 'default' => 1, 'min' => 0, 'max' => 100, 'help' => '仅运营参考/兼容;实际价格以文章付费设置为准。'],
['key' => 'download_daily_limit', 'label' => '每日下载限制', 'type' => 'number', 'default' => 0, 'min' => 0, 'help' => '0为不限制'],
['key' => 'download_link_expire', 'label' => '下载链接有效期(分钟)', 'type' => 'number', 'default' => 30, 'min' => 5, 'max' => 1440],
['key' => 'download_speed_limit', 'label' => '下载速度限制(KB/s)', 'type' => 'number', 'default' => 0, 'min' => 0, 'help' => '0为不限制'],
]],
['key' => 'vip', 'title' => 'VIP 特权', 'fields' => [
['key' => 'download_vip_free', 'label' => 'VIP 免费下载', 'type' => 'switch', 'default' => false],
+5 -22
View File
@@ -295,16 +295,11 @@ class Download {
}
$target_url = esc_url_raw((string) $meta['downloads'][$idx]['url']);
$speed_kb = 0;
$uid_speed = (int) ($row['user_id'] ?? 0);
if ($uid_speed > 0 && function_exists('aksrt_get_user_download_speed')) {
$speed_kb = aksrt_get_user_download_speed($uid_speed);
}
// Local attachment / uploads file: optional throttled stream (Zibll speed limit).
// Local attachment / uploads file: stream without artificial throttling.
$local_path = $this->resolve_local_download_path($target_url);
if ($local_path !== '' && is_readable($local_path)) {
$this->stream_local_file($local_path, $speed_kb);
$this->stream_local_file($local_path);
exit;
}
@@ -347,9 +342,9 @@ class Download {
}
/**
* Stream a local file with optional KB/s throttle.
* Stream a local file.
*/
private function stream_local_file(string $path, int $speed_kb = 0): void {
private function stream_local_file(string $path): void {
$filename = basename($path);
$size = filesize($path);
if ($size === false) {
@@ -364,21 +359,12 @@ class Download {
header('Content-Length: ' . (string) $size);
$chunk = 1024 * 64; // 64KB
$sleep_us = 0;
if ($speed_kb > 0) {
// Emit ~speed_kb KB per second using fixed 64KB chunks when possible.
$bytes_per_sec = max(1024, $speed_kb * 1024);
$chunk = min(1024 * 64, $bytes_per_sec);
$chunk = max(1024, $chunk);
// Sleep so chunk_bytes / second ≈ bytes_per_sec.
$sleep_us = (int) max(0, (int) round(($chunk / $bytes_per_sec) * 1000000) - 1000);
}
$fh = fopen($path, 'rb');
if (!$fh) {
$this->fail_410();
}
// Disable output compression for accurate Content-Length / throttle.
// Disable output compression so Content-Length remains accurate.
if (function_exists('apache_setenv')) {
@apache_setenv('no-gzip', '1');
}
@@ -392,9 +378,6 @@ class Download {
if (function_exists('flush')) {
flush();
}
if ($sleep_us > 0) {
usleep($sleep_us);
}
}
fclose($fh);
}
+5 -1
View File
@@ -41,6 +41,7 @@ trait VipServiceModal {
'name' => (string) ($levels[$level]['name'] ?? ('VIP' . $level)),
'desc' => (string) ($levels[$level]['desc'] ?? ''),
'equity' => $equity,
'img_icon' => esc_url_raw((string) ($levels[$level]['img_icon'] ?? '')),
];
}
@@ -161,7 +162,10 @@ trait VipServiceModal {
? aksrt_format_vip_equity_html($equity, 'mb10 relative')
: '';
$icon = '<i class="fas fa-gem" aria-hidden="true"></i>';
$icon_url = esc_url((string) ($levels[$level]['img_icon'] ?? ''));
$icon = $icon_url !== ''
? '<img class="aksrt-vip-level-icon" src="' . $icon_url . '" alt="" loading="lazy" decoding="async" />'
: '<i class="fas fa-gem" aria-hidden="true"></i>';
$html = '<div class="vip-card pointer level-' . $level . ' vip-theme' . $level . $cls . '" vip-level="' . $level . '">';
$html .= '<div class="vip-baicon" aria-hidden="true">' . $icon . '</div>';
$html .= '<div class="vip-img abs-right">' . $icon . '</div>';
+19 -5
View File
@@ -122,6 +122,23 @@ class PaymentRuntime {
];
}
/**
* Resolve a configured VIP icon, falling back to the bundled level asset.
*/
private static function get_vip_icon_url(int $level, string $configured): string {
$configured = esc_url_raw($configured);
if ($configured !== '') {
return $configured;
}
$filename = 'vip-' . $level . '.svg';
if (defined('AKSRT_DIR') && is_file(AKSRT_DIR . '/assets/img/user/vip/' . $filename)) {
return defined('AKSRT_URI') ? AKSRT_URI . '/assets/img/user/vip/' . $filename : '';
}
return '';
}
/**
* Dual-level VIP settings (Zibll pay_user_vip_1 / pay_user_vip_2).
*
@@ -190,27 +207,24 @@ class PaymentRuntime {
'name' => $name1,
'desc' => sanitize_text_field((string) ($settings['pay_user_vip_1_desc'] ?? __('尊享一级会员特权', 'aksrt'))),
'equity' => wp_kses((string) (($settings['pay_user_vip_1_equity'] ?? '') !== '' ? $settings['pay_user_vip_1_equity'] : '<li>免费下载部分资源</li><li>会员专属身份标识</li><li>付费内容会员价</li>'), $allowed_equity),
'img_icon' => esc_url_raw((string) ($settings['vip_1_img_icon'] ?? '')),
'img_icon' => self::get_vip_icon_url(1, (string) ($settings['vip_1_img_icon'] ?? '')),
'product_s' => !isset($settings['vip_1_product_s']) || !empty($settings['vip_1_product_s']),
'products_raw' => $products_1,
'download_limit' => max(0, min(9999, (int) ($settings['pay_download_limit_vip_1'] ?? 0))),
'download_speed' => max(0, min(99999, (int) ($settings['pay_download_speed_vip_1'] ?? 0))),
],
2 => [
'enabled' => $vip2_enabled,
'name' => $name2,
'desc' => sanitize_text_field((string) ($settings['pay_user_vip_2_desc'] ?? __('尊享二级会员特权', 'aksrt'))),
'equity' => wp_kses((string) (($settings['pay_user_vip_2_equity'] ?? '') !== '' ? $settings['pay_user_vip_2_equity'] : '<li>更高免费下载额度</li><li>更高等级身份标识</li><li>更多付费内容会员价</li>'), $allowed_equity),
'img_icon' => esc_url_raw((string) ($settings['vip_2_img_icon'] ?? '')),
'img_icon' => self::get_vip_icon_url(2, (string) ($settings['vip_2_img_icon'] ?? '')),
'product_s' => !isset($settings['vip_2_product_s']) || !empty($settings['vip_2_product_s']),
'products_raw' => $products_2,
'download_limit' => max(0, min(9999, (int) ($settings['pay_download_limit_vip_2'] ?? 0))),
'download_speed' => max(0, min(99999, (int) ($settings['pay_download_speed_vip_2'] ?? 0))),
],
],
'benefit' => [
'download_limit' => max(0, min(9999, (int) ($settings['pay_download_limit'] ?? 0))),
'download_speed' => max(0, min(99999, (int) ($settings['pay_download_speed'] ?? 0))),
'pass_charge' => !empty($settings['pay_vip_pass_charge_s']),
'pass_charge_desc' => sanitize_textarea_field((string) ($settings['pay_vip_pass_charge_desc'] ?? '')),
'pass_charge_only_password' => !isset($settings['pay_vip_pass_charge_only_password']) || !empty($settings['pay_vip_pass_charge_only_password']),