• 今天分享一个汽水音乐解析模板,直接丢进模板子比目录直接使用,喜欢自行部署!
  • 定位子比目录 :/wp-content/themes/zibll/pages(创建一个php文件,代码直接丢进去即可!)

图片[1]-子比主题 – 汽水音乐解析模板-zibll综合交流社区-zibll子比主题-WordPress主题模板-zibll子比主题

图片[2]-子比主题 – 汽水音乐解析模板-zibll综合交流社区-zibll子比主题-WordPress主题模板-zibll子比主题

模板代码:

<?php
// IP限制相关配置
define('IP_LIMIT_PER_MINUTE', 3); // 每分钟最大请求次数
define('IP_LIMIT_WINDOW', 60); // 时间窗口(秒)

// IP限制函数
function checkIpLimit() {
    $ip = $_SERVER['REMOTE_ADDR'];
    $cache_key = 'ip_limit_' . $ip;
    $current_time = time();
    
    // 获取该IP的请求记录
    $requests = get_transient($cache_key);
    if (!$requests) {
        $requests = array();
    }
    
    // 清理过期的请求记录
    $requests = array_filter($requests, function($timestamp) use ($current_time) {
        return $timestamp > ($current_time - IP_LIMIT_WINDOW);
    });
    
    // 计算剩余请求次数
    $remaining_requests = IP_LIMIT_PER_MINUTE - count($requests);
    
    // 如果超过限制,计算需要等待的时间
    if ($remaining_requests <= 0) {
        $oldest_request = min($requests);
        $wait_time = $oldest_request + IP_LIMIT_WINDOW - $current_time;
        return array(
            'allowed' => false,
            'remaining' => 0,
            'wait_time' => $wait_time
        );
    }
    
    // 添加新的请求记录
    $requests[] = $current_time;
    set_transient($cache_key, $requests, IP_LIMIT_WINDOW);
    
    return array(
        'allowed' => true,
        'remaining' => $remaining_requests - 1
    );
}

// 修改代理函数
function proxyAudio($url) {
    // 确保在开始处理之前清除所有输出缓冲
    while (ob_get_level()) {
        ob_end_clean();
    }
    
    $ch = curl_init();
    curl_setopt($ch, CURLOPT_URL, $url);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
    curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
    curl_setopt($ch, CURLOPT_ENCODING, '');
    
    // 添加更多请求头来模拟浏览器行为
    $headers = [
        'User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',
        'Accept: */*',
        'Accept-Language: zh-CN,zh;q=0.9,en;q=0.8',
        'Accept-Encoding: gzip, deflate, br',
        'Connection: keep-alive',
        'Referer: https://music.douyin.com/',
        'Origin: https://music.douyin.com',
        'Sec-Fetch-Dest: audio',
        'Sec-Fetch-Mode: cors',
        'Sec-Fetch-Site: cross-site',
        'Range: bytes=0-',
        'Cache-Control: no-cache',
        'Pragma: no-cache'
    ];
    curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
    
    $response = curl_exec($ch);
    $contentType = curl_getinfo($ch, CURLINFO_CONTENT_TYPE);
    $contentLength = curl_getinfo($ch, CURLINFO_CONTENT_LENGTH_DOWNLOAD);
    $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
    
    if (curl_errno($ch)) {
        error_log("CURL Error for proxyAudio URL {$url}: " . curl_error($ch));
        header('HTTP/1.1 500 Internal Server Error');
        header('Content-Type: application/json; charset=utf-8');
        echo json_encode(['error' => '服务器获取音频失败'], JSON_UNESCAPED_UNICODE);
        curl_close($ch);
        exit;
    }
    
    curl_close($ch);
    
    // 检查HTTP状态码
    if ($httpCode !== 200 && $httpCode !== 206) {
        header('HTTP/1.1 ' . $httpCode);
        header('Content-Type: application/json; charset=utf-8');
        echo json_encode(['error' => '获取音频文件失败,HTTP状态码: ' . $httpCode], JSON_UNESCAPED_UNICODE);
        exit;
    }
    
    // 设置响应头
    header('Content-Type: ' . ($contentType ? $contentType : 'audio/x-m4a'));
    header('Content-Disposition: attachment; filename="music.m4a"');
    if ($contentLength) {
        header('Content-Length: ' . $contentLength);
    }
    header('Cache-Control: no-cache, must-revalidate');
    header('Pragma: no-cache');
    header('Expires: 0');
    
    // 直接输出响应内容
    echo $response;
    exit;
}

// 保持原有的解析函数
function getMusicInfo($type = 'json', $url = '')
{
    if (strstr($url, 'qishui.douyin.com')) {
        $url = headers($url);
        preg_match('/track_id=(\d+)/', $url, $match);
    } else {
        preg_match('/track_id=(\d+)/', $url, $match);
    }
    
    if (empty($match[1])) {
        throw new Exception('无法获取音乐ID');
    }
    
    $curl = curl('https://music.douyin.com/qishui/share/track?track_id=' . $match[1]);
    
    if (empty($curl)) {
        throw new Exception('获取音乐信息失败');
    }

    // 匹配 application/ld+json 数据,获取标题和封面
    preg_match('/<script data-react-helmet="true" type="application\/ld\+json">(.*?)<\/script>/s', $curl, $ldJsonMatches);
    if (isset($ldJsonMatches[1])) {
        $ldJsonData = json_decode(urldecode($ldJsonMatches[1]), true);
        $title = $ldJsonData['title'] ?? '';
        $cover = isset($ldJsonData['images']) && count($ldJsonData['images']) > 0 ? $ldJsonData['images'][0] : '';
    } else {
        // 尝试从其他位置获取标题
        preg_match('/<title>(.*?)<\/title>/s', $curl, $titleMatch);
        $title = isset($titleMatch[1]) ? trim($titleMatch[1]) : '';
        
        // 尝试从其他位置获取封面
        preg_match('/<meta property="og:image" content="(.*?)"/s', $curl, $coverMatch);
        $cover = isset($coverMatch[1]) ? $coverMatch[1] : '';
    }

    $jsJsonPattern = '/<script\s+async=""\s+data-script-src="modern-inline">_ROUTER_DATA\s*=\s*({[\s\S]*?});/';
    preg_match($jsJsonPattern, $curl, $jsJsonMatches);

    if (isset($jsJsonMatches[1])) {
        $jsonStr = $jsJsonMatches[1];
        $jsonData = json_decode(trim($jsonStr), true);
        
        // 获取音乐URL
        $musicUrl = '';
        if ($jsonData !== null) {
            if (isset($jsonData['loaderData']['track_page']['audioWithLyricsOption']['url'])) {
                $musicUrl = $jsonData['loaderData']['track_page']['audioWithLyricsOption']['url'];
            } elseif (isset($jsonData['loaderData']['track_page']['audioOption']['url'])) {
                $musicUrl = $jsonData['loaderData']['track_page']['audioOption']['url'];
            }
        }

        // 提取歌词
        $lrcLyrics = [];
        if ($jsonData !== null) {
            $lyricsData = $jsonData['loaderData']['track_page']['audioWithLyricsOption']['lyrics'] ?? 
                         $jsonData['loaderData']['track_page']['lyrics'] ?? null;
            
            if ($lyricsData && isset($lyricsData['sentences'])) {
                $sentences = $lyricsData['sentences'];
                foreach ($sentences as $sentence) {
                    if (isset($sentence['startMs']) && isset($sentence['words'])) {
                        $startMs = $sentence['startMs'];
                        $sentenceText = '';
                        foreach ($sentence['words'] as $word) {
                            if (isset($word['text'])) {
                                $sentenceText .= $word['text'];
                            }
                        }
                        $minutes = floor($startMs / 60000);
                        $seconds = floor(($startMs % 60000) / 1000);
                        $milliseconds = $startMs % 1000;
                        $timeTag = sprintf("[%02d:%02d.%03d]", $minutes, $seconds, $milliseconds);
                        $lrcLyrics[] = $timeTag . $sentenceText;
                    }
                }
            }
        }
        $lyrics = implode("\n", $lrcLyrics);
    } else {
        $musicUrl = '';
        $lyrics = '';
    }

    // 构建结果数组
    $info = array(
        'name' => $title ?: '未知歌曲',
        'url' => $musicUrl,
        'cover' => $cover ?: 'https://p3-pc.douyinpic.com/aweme/1080x1080/aweme-avatar/default_avatar.jpeg',
        'lyrics' => $lyrics,
        'core' => '抖音汽水音乐解析',
        'copyright' => '开心宝:joyb.cc'
    );

    if (!empty($info['url'])) {
        return json_encode($info, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
    } else {
        throw new Exception('没有找到相关音乐');
    }
}

function curl($url, $data = '', $cookie = '', $headers = [])
{
    $con = curl_init((string)$url);
    curl_setopt($con, CURLOPT_HEADER, false);
    curl_setopt($con, CURLOPT_SSL_VERIFYPEER, false);
    curl_setopt($con, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($con, CURLOPT_USERAGENT, 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36');
    
    if (!empty($headers)) {
        curl_setopt($con, CURLOPT_HTTPHEADER, $headers);
    }
    if (!empty($cookie)) {
        curl_setopt($con, CURLOPT_COOKIE, $cookie);
    }
    if (!empty($data)) {
        curl_setopt($con, CURLOPT_POST, true);
        curl_setopt($con, CURLOPT_POSTFIELDS, $data);
    }
    curl_setopt($con, CURLOPT_TIMEOUT, 5000);
    $result = curl_exec($con);
    
    if ($result === false) {
        // curl_error($con) 会提供更详细的错误信息
        throw new Exception('CURL错误: ' . curl_error($con));
    }
    
    curl_close($con);
    return $result;
}

function headers($url)
{
    $headers = get_headers($url, 1);
    if (isset($headers['Location'])) {
        if (is_array($headers['Location'])) {
            $url = end($headers['Location']);
        } else {
            $url = $headers['Location'];
        }
    }
    return $url;
}


// **从这里开始,是请求处理和页面渲染的分支逻辑**
// **这些请求必须在任何HTML输出之前处理**

// 修改AJAX处理部分 - 最优先处理,因为它们不应该输出任何HTML
if(isset($_GET['ajax']) && $_GET['ajax'] == '1') {
    header('Content-Type: application/json; charset=utf-8');
    
    // 检查IP限制
    $ip_limit_result = checkIpLimit();
    if (!$ip_limit_result['allowed']) {
        $wait_minutes = ceil($ip_limit_result['wait_time'] / 60);
        echo json_encode([
            'code' => 429, 
            'msg' => sprintf('请求过于频繁,请等待 %d 分钟后再试', $wait_minutes),
            'wait_time' => $ip_limit_result['wait_time']
        ], JSON_UNESCAPED_UNICODE);
        exit;
    }
    
    // 检查用户是否登录
    if (!is_user_logged_in()) {
        echo json_encode(['code' => 403, 'msg' => '请先登录'], JSON_UNESCAPED_UNICODE);
        exit;
    }

    // 检查用户积分是否足够
    $user_id = get_current_user_id();
    $user_points = zibpay_get_user_points($user_id);
    if ($user_points < 5) {
        echo json_encode(['code' => 403, 'msg' => '积分不足,需要5积分'], JSON_UNESCAPED_UNICODE);
        exit;
    }

    $url = isset($_GET['url']) ? $_GET['url'] : '';
    $type = isset($_GET['type']) ? $_GET['type'] : 'json';
    
    try {
        if ($type !== '' && $url !== '') {
            // 解析音乐
            $result = json_decode(getMusicInfo($type, $url), true);
            
            if ($result && isset($result['url'])) {
                // 扣除积分
                $points_data = array(
                    'order_num' => 'music_parse_' . time(), // 生成订单号
                    'value'     => -5, // 扣除5积分
                    'type'      => '音乐解析', // 类型说明
                    'desc'      => '解析音乐《' . $result['name'] . '》', // 说明
                );
                zibpay_update_user_points($user_id, $points_data);
                
                echo getMusicInfo($type, $url);
            } else {
                echo json_encode(['code' => 404, 'msg' => '解析失败,未找到音乐信息'], JSON_UNESCAPED_UNICODE);
            }
        } else {
            echo json_encode(['code' => 404, 'msg' => '请补全参数'], JSON_UNESCAPED_UNICODE);
        }
    } catch (Exception $e) {
        echo json_encode(['code' => 500, 'msg' => $e->getMessage()], JSON_UNESCAPED_UNICODE);
    }
    exit; // 确保AJAX请求处理后立即退出
}

// 添加音频代理处理 - 优先处理,因为它们不应该输出任何HTML
if(isset($_GET['proxy']) && $_GET['proxy'] == '1') {
    $audioUrl = isset($_GET['url']) ? $_GET['url'] : '';
    if (!empty($audioUrl)) {
        proxyAudio($audioUrl); // proxyAudio 函数内部会处理输出和退出
    } else {
        header('Content-Type: application/json; charset=utf-8');
        header('HTTP/1.1 400 Bad Request');
        echo json_encode(['error' => 'Missing audio URL for proxy'], JSON_UNESCAPED_UNICODE);
        exit;
    }
    exit; // 确保代理请求处理后立即退出 (即使proxyAudio内部已经exit, 这里的exit是兜底)
}

// 在PHP部分添加获取积分的处理 - 优先处理
if (isset($_GET['get_points']) && $_GET['get_points'] == '1') {
    header('Content-Type: application/json; charset=utf-8');
    $user_id = get_current_user_id();
    $points = zibpay_get_user_points($user_id);
    echo json_encode(['points' => $points]);
    exit; // 确保积分请求处理后立即退出
}

// **只有当上述所有特殊请求都没有被处理时,才渲染完整的页面模板**

// 在PHP部分添加登录状态检查
$is_logged_in = is_user_logged_in();
$user_points = $is_logged_in ? zibpay_get_user_points(get_current_user_id()) : 0;

get_header(); // 现在,get_header() 只会在渲染完整页面时调用
?>

<div class="qsmusic-container">
    <div class="qsmusic-form">
        <h2>汽水音乐解析</h2>
        <?php if ($is_logged_in): ?>
        <div class="user-info">
            <div class="points-card">
                <div class="points-header">
                    <div class="points-icon">🎵</div>
                    <div class="points-title">音乐解析</div>
                </div>
                <div class="points-body">
                    <div class="points-item">
                        <span class="points-label">当前积分</span>
                        <span class="points-value" id="currentPoints"><?php echo $user_points; ?></span>
                    </div>
                    <div class="points-item">
                        <span class="points-label">解析消耗</span>
                        <span class="points-cost">5 积分/次</span>
                    </div>
                </div>
            </div>
            <div class="parse-form">
                <div class="input-wrapper">
                    <input type="text" id="musicUrl" placeholder="请输入汽水音乐分享链接" class="form-control">
                    <button onclick="parseMusic()" class="btn btn-primary">
                        <span class="btn-icon">🎯</span>
                        <span class="btn-text">开始解析</span>
                    </button>
                </div>
            </div>
        </div>
        <?php else: ?>
        <div class="points-notice not-logged-in">
            <div class="notice-content">
                <i class="fa fa-lock"></i>
                <div class="notice-text">
                    <h4>请先登录后再使用音乐解析功能</h4>
                    <p>登录后即可使用积分解析音乐</p>
                </div>
            </div>
            <div class="notice-actions">
                <a href="<?php echo wp_login_url(get_permalink()); ?>" class="btn btn-primary">立即登录</a>
                <a href="<?php echo wp_registration_url(); ?>" class="btn btn-outline">注册账号</a>
            </div>
        </div>
        
        <!-- 效果预览区 -->
        <div class="preview-section">
            <h3 class="preview-title">功能预览</h3>
            <div class="preview-content">
                <div class="preview-image">
                    <img src="https://joyb.cc/wp-content/uploads/2025/06/20250613164036412-汽水音乐解析演示图-scaled.webp" alt="音乐解析效果预览" />
                    <div class="preview-overlay">
                        <p>登录后即可体验完整功能</p>
                    </div>
                </div>
            </div>
        </div>
        <?php endif; ?>
    </div>
    
    <div id="result" class="qsmusic-result" style="display: none;">
        <div class="music-info">
            <h3 id="title"></h3>
            <div class="player-actions">
                <a id="downloadLink" href="#" download class="btn btn-secondary">
                    <span class="download-icon">⬇️</span>
                    <span class="download-text">下载音乐</span>
                    <span id="fileSize" class="file-size"></span>
                </a>
            </div>
            <div id="lyrics" class="lyrics"></div>
        </div>
    </div>
    
    <!-- 修改调试信息区域的HTML结构 -->
    <div id="debug" class="debug-container">
        <h4>解析详情</h4>
        <pre id="debugInfo"></pre>
    </div>
</div>

<style>
/* 整个容器的样式 */
.qsmusic-container {
    max-width: 800px;
    margin: 40px auto;
    padding: 40px;
    background: #fff;
    border-radius: 16px;
    box-shadow: 0 4px 20px rgba(0, 0, 0, 0.08);
    min-height: calc(100vh - 200px);
    display: flex;
    flex-direction: column;
    transition: all 0.3s ease;
}

/* 夜间模式样式 */
body.dark-theme .qsmusic-container {
    background: #1a1a1a;
    box-shadow: 0 4px 20px rgba(0, 0, 0, 0.2);
}

.qsmusic-container .qsmusic-form {
    flex: 1;
    display: flex;
    flex-direction: column;
    justify-content: center;
    text-align: center;
}

.qsmusic-container .qsmusic-form h2 {
    color: #2c3e50;
    margin-bottom: 40px;
    font-size: 32px;
    font-weight: 600;
    transition: color 0.3s ease;
}

body.dark-theme .qsmusic-container .qsmusic-form h2 {
    color: #e0e0e0;
}

.qsmusic-container .user-info {
    display: flex;
    flex-direction: column;
    gap: 32px;
}

.qsmusic-container .points-card {
    background: linear-gradient(135deg, #6c5ce7, #a8a4e6);
    border-radius: 16px;
    padding: 30px;
    color: white;
    box-shadow: 0 4px 15px rgba(108, 92, 231, 0.2);
    transition: all 0.3s ease;
}

body.dark-theme .qsmusic-container .points-card {
    background: linear-gradient(135deg, #5b4bc4, #8a85d6);
    box-shadow: 0 4px 15px rgba(91, 75, 196, 0.3);
}

.qsmusic-container .points-header {
    display: flex;
    align-items: center;
    margin-bottom: 24px;
}

.qsmusic-container .points-icon {
    font-size: 32px;
    margin-right: 16px;
}

.qsmusic-container .points-title {
    font-size: 24px;
    font-weight: 500;
}

.qsmusic-container .points-body {
    display: flex;
    justify-content: space-between;
    gap: 24px;
}

.qsmusic-container .points-item {
    flex: 1;
    text-align: center;
    padding: 20px;
    background: rgba(255, 255, 255, 0.1);
    border-radius: 12px;
    backdrop-filter: blur(5px);
}

.qsmusic-container .points-label {
    display: block;
    font-size: 16px;
    opacity: 0.9;
    margin-bottom: 8px;
}

.qsmusic-container .points-value {
    font-size: 32px;
    font-weight: 600;
}

.qsmusic-container .points-cost {
    font-size: 28px;
    font-weight: 500;
    color: #ffd700;
}

.qsmusic-container .parse-form {
    background: #f8f9fa;
    border-radius: 16px;
    padding: 30px;
    border: 1px solid #e9ecef;
    transition: all 0.3s ease;
}

body.dark-theme .qsmusic-container .parse-form {
    background: #2a2a2a;
    border-color: #3a3a3a;
}

.qsmusic-container .input-wrapper {
    display: flex;
    gap: 16px;
    margin-bottom: 16px;
}

/* 输入框和按钮样式 */
.qsmusic-container #musicUrl {
    flex: 1;
    padding: 12px 15px;
    border: 2px solid #e0e0e0;
    border-radius: 8px;
    font-size: 14px;
    transition: all 0.3s ease;
    height: 48px;
    box-sizing: border-box;
}

.qsmusic-container #musicUrl:focus {
    border-color: #6c5ce7;
    outline: none;
    box-shadow: 0 0 0 3px rgba(108,92,231,0.1);
}

.qsmusic-container .btn {
    padding: 12px 24px;
    border: none;
    border-radius: 8px;
    font-size: 14px;
    font-weight: 500;
    cursor: pointer;
    transition: all 0.3s ease;
    height: 48px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    text-decoration: none;
}

.qsmusic-container .btn-primary {
    background: #6c5ce7;
    color: white;
}

.qsmusic-container .btn-primary:hover {
    background: #5b4bc4;
    transform: translateY(-1px);
}

.qsmusic-container .btn-secondary {
    background: #6c757d;
    color: white;
}

.qsmusic-container .btn-secondary:hover {
    background: #5a6268;
    transform: translateY(-1px);
}

.qsmusic-container .btn-icon {
    font-size: 18px;
}

.qsmusic-container .form-tips {
    display: flex;
    align-items: center;
    gap: 10px;
    color: #6c757d;
    font-size: 16px;
    margin-top: 16px;
    transition: color 0.3s ease;
}

body.dark-theme .qsmusic-container .form-tips {
    color: #a0a0a0;
}

.qsmusic-container .tip-icon {
    font-size: 20px;
}

.qsmusic-container .music-info {
    background: #f8f9fa;
    border-radius: 12px;
    padding: 20px;
    margin-top: 20px;
    transition: all 0.3s ease;
}

body.dark-theme .qsmusic-container .music-info {
    background: #2a2a2a;
    border: 1px solid #3a3a3a;
}

.qsmusic-container .music-info h3 {
    color: #2c3e50;
    font-size: 20px;
    margin-bottom: 16px;
    text-align: center;
}

.qsmusic-container .player-actions {
    display: flex;
    justify-content: center;
    margin-bottom: 20px;
}

/* 歌词区域滚动条样式 */
.qsmusic-container .lyrics {
    max-height: 300px;
    overflow-y: auto;
    padding: 16px;
    background: white;
    border-radius: 8px;
    font-size: 14px;
    line-height: 1.6;
    color: #495057;
    transition: all 0.3s ease;
    scrollbar-width: thin; /* Firefox */
    scrollbar-color: #6c5ce7 #f8f9fa; /* Firefox */
}

/* Webkit浏览器的滚动条样式 */
.qsmusic-container .lyrics::-webkit-scrollbar {
    width: 8px;
}

.qsmusic-container .lyrics::-webkit-scrollbar-track {
    background: #f8f9fa;
    border-radius: 4px;
}

.qsmusic-container .lyrics::-webkit-scrollbar-thumb {
    background: #6c5ce7;
    border-radius: 4px;
    transition: all 0.3s ease;
}

.qsmusic-container .lyrics::-webkit-scrollbar-thumb:hover {
    background: #5b4bc4;
}

/* 夜间模式滚动条样式 */
body.dark-theme .qsmusic-container .lyrics {
    background: #333;
    color: #e0e0e0;
    scrollbar-color: #a8a4e6 #2a2a2a; /* Firefox */
}

body.dark-theme .qsmusic-container .lyrics::-webkit-scrollbar-track {
    background: #2a2a2a;
}

body.dark-theme .qsmusic-container .lyrics::-webkit-scrollbar-thumb {
    background: #a8a4e6;
}

body.dark-theme .qsmusic-container .lyrics::-webkit-scrollbar-thumb:hover {
    background: #8a85d6;
}

/* 歌词行样式 */
.qsmusic-container .lyrics div {
    padding: 4px 0;
    transition: all 0.3s ease;
}

.qsmusic-container .lyrics div:hover {
    color: #6c5ce7;
    transform: translateX(4px);
}

body.dark-theme .qsmusic-container .lyrics div:hover {
    color: #a8a4e6;
}

/* 无歌词提示样式 */
.qsmusic-container .no-lyrics {
    text-align: center;
    color: #6c757d;
    padding: 20px;
    font-style: italic;
}

body.dark-theme .qsmusic-container .no-lyrics {
    color: #a0a0a0;
}

.qsmusic-container .file-size {
    font-size: 0.9em;
    opacity: 0.8;
    margin-left: 4px;
}

/* 调试信息容器样式 */
.qsmusic-container .debug-container {
    display: none;
    margin-top: 20px;
    padding: 20px;
    background: #f8f9fa;
    border-radius: 12px;
    font-family: 'Consolas', 'Monaco', monospace;
    font-size: 14px;
    line-height: 1.6;
    color: #2c3e50;
    border: 1px solid #e9ecef;
    transition: all 0.3s ease;
}

body.dark-theme .qsmusic-container .debug-container {
    background: #1a1a1a;
    border-color: #2a2a2a;
    color: #e0e0e0;
}

.qsmusic-container .debug-container h4 {
    margin: 0 0 15px 0;
    color: #2c3e50;
    font-size: 16px;
    font-weight: 600;
    transition: color 0.3s ease;
    text-align: center;
    position: relative;
    padding-bottom: 10px;
}

.qsmusic-container .debug-container h4:after {
    content: '';
    position: absolute;
    bottom: 0;
    left: 50%;
    transform: translateX(-50%);
    width: 40px;
    height: 2px;
    background: #6c5ce7;
    border-radius: 2px;
}

body.dark-theme .qsmusic-container .debug-container h4 {
    color: #e0e0e0;
}

body.dark-theme .qsmusic-container .debug-container h4:after {
    background: #a8a4e6;
}

.qsmusic-container #debugInfo {
    margin: 0;
    white-space: pre-wrap;
    word-break: break-all;
    background: #fff;
    padding: 15px;
    border-radius: 8px;
    border: 1px solid #e9ecef;
    color: #495057;
    transition: all 0.3s ease;
}

body.dark-theme .qsmusic-container #debugInfo {
    background: #2a2a2a;
    border-color: #3a3a3a;
    color: #d0d0d0;
}

/* 调试信息中的URL和状态码样式 */
.qsmusic-container #debugInfo {
    font-family: 'Consolas', 'Monaco', monospace;
}

.qsmusic-container #debugInfo a {
    color: #6c5ce7;
    text-decoration: none;
    transition: color 0.3s ease;
}

body.dark-theme .qsmusic-container #debugInfo a {
    color: #a8a4e6;
}

.qsmusic-container #debugInfo a:hover {
    text-decoration: underline;
}

/* 调试信息中的错误信息样式 */
.qsmusic-container #debugInfo .error {
    color: #e74c3c;
    font-weight: 500;
}

body.dark-theme .qsmusic-container #debugInfo .error {
    color: #ff6b6b;
}

/* 调试信息中的成功信息样式 */
.qsmusic-container #debugInfo .success {
    color: #2ecc71;
    font-weight: 500;
}

body.dark-theme .qsmusic-container #debugInfo .success {
    color: #69db7c;
}

/* 调试信息中的警告信息样式 */
.qsmusic-container #debugInfo .warning {
    color: #f1c40f;
    font-weight: 500;
}

body.dark-theme .qsmusic-container #debugInfo .warning {
    color: #ffd43b;
}

/* 调试信息中的信息样式 */
.qsmusic-container #debugInfo .info {
    color: #3498db;
    font-weight: 500;
}

body.dark-theme .qsmusic-container #debugInfo .info {
    color: #74c0fc;
}

/* 响应式设计 */
@media (max-width: 768px) {
    .qsmusic-container {
        margin: 20px;
        padding: 30px;
        min-height: calc(100vh - 100px);
    }

    body.dark-theme .qsmusic-container {
        background: #1a1a1a;
    }

    .qsmusic-container .login-notice {
        padding: 30px 20px;
    }

    body.dark-theme .qsmusic-container .login-notice {
        background: #2a2a2a;
    }

    .qsmusic-container .notice-icon {
        font-size: 40px;
        margin-bottom: 20px;
    }

    .qsmusic-container .notice-content p {
        font-size: 16px;
    }

    .qsmusic-container .notice-desc {
        font-size: 14px;
        margin: 10px 0 20px !important;
    }

    .qsmusic-container .login-buttons {
        flex-direction: column;
        gap: 12px;
    }

    .qsmusic-container .login-buttons .btn {
        width: 100%;
        padding: 12px 24px;
    }

    .qsmusic-container .points-body {
        flex-direction: column;
        gap: 12px;
    }
    
    .qsmusic-container .input-wrapper {
        flex-direction: column;
    }
    
    .qsmusic-container .btn {
        width: 100%;
    }

    .qsmusic-container .debug-container {
        padding: 15px;
        font-size: 13px;
    }

    .qsmusic-container #debugInfo {
        padding: 12px;
    }
}

/* 效果预览区样式 */
.qsmusic-container .preview-section {
    margin-top: 30px;
    padding: 20px;
    background: white;
    border-radius: 12px;
    box-shadow: 0 2px 12px rgba(0,0,0,0.08);
    transition: all 0.3s ease;
}

.qsmusic-container .preview-title {
    text-align: center;
    color: #333;
    margin-bottom: 20px;
    font-size: 1.2em;
    position: relative;
    padding-bottom: 10px;
}

.qsmusic-container .preview-title:after {
    content: '';
    position: absolute;
    bottom: 0;
    left: 50%;
    transform: translateX(-50%);
    width: 40px;
    height: 2px;
    background: #6c5ce7;
}

.qsmusic-container .preview-content {
    padding: 10px;
}

.qsmusic-container .preview-image {
    position: relative;
    border-radius: 8px;
    overflow: hidden;
    box-shadow: 0 4px 12px rgba(0,0,0,0.1);
}

.qsmusic-container .preview-image img {
    width: 100%;
    height: auto;
    display: block;
    transition: all 0.3s ease;
}

.qsmusic-container .preview-overlay {
    position: absolute;
    top: 0;
    left: 0;
    right: 0;
    bottom: 0;
    background: rgba(0,0,0,0.5);
    display: flex;
    align-items: center;
    justify-content: center;
    opacity: 0;
    transition: all 0.3s ease;
}

.qsmusic-container .preview-image:hover .preview-overlay {
    opacity: 1;
}

.qsmusic-container .preview-overlay p {
    color: white;
    font-size: 18px;
    text-align: center;
    padding: 20px;
    background: rgba(108,92,231,0.9);
    border-radius: 8px;
    transform: translateY(20px);
    transition: all 0.3s ease;
}

.qsmusic-container .preview-image:hover .preview-overlay p {
    transform: translateY(0);
}

/* 夜间模式样式 */
body.dark-theme .qsmusic-container .preview-section {
    background: #2a2a2a;
}

body.dark-theme .qsmusic-container .preview-title {
    color: #e0e0e0;
}

/* 响应式调整 */
@media (max-width: 768px) {
    .qsmusic-container .preview-section {
        padding: 15px;
    }
    
    .qsmusic-container .preview-overlay p {
        font-size: 16px;
        padding: 15px;
    }
}
</style>

<script>
// 修改获取当前积分的函数
async function getCurrentPoints() {
    try {
        const response = await fetch(window.location.href + '?get_points=1');
        const data = await response.json();
        if (data.points !== undefined) {
            document.getElementById('currentPoints').textContent = data.points;
        }
    } catch (error) {
        console.error('Error fetching points:', error);
        document.getElementById('currentPoints').textContent = '获取失败';
    }
}

// 只在登录状态下获取积分
<?php if ($is_logged_in): ?>
document.addEventListener('DOMContentLoaded', getCurrentPoints);
<?php endif; ?>

async function fetchAudio(url) {
    try {
        const response = await fetch(url);
        if (!response.ok) {
            throw new Error(`HTTP error! status: ${response.status}`);
        }
        const blob = await response.blob();
        return {
            size: blob.size
        };
    } catch (error) {
        console.error('Error fetching audio:', error);
        throw error;
    }
}

function formatFileSize(bytes) {
    if (bytes === 0) return '0 B';
    const k = 1024;
    const sizes = ['B', 'KB', 'MB', 'GB'];
    const i = Math.floor(Math.log(bytes) / Math.log(k));
    return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];
}

// 修改自动提取链接的函数
function extractMusicUrl(text) {
    // 匹配抖音/快手分享链接的正则表达式
    const urlPattern = /(https?:\/\/[^\s]+)/g;
    const matches = text.match(urlPattern);
    
    if (matches) {
        // 找到第一个匹配的链接
        let url = matches[0];
        // 移除链接末尾可能的多余字符
        url = url.replace(/[.,;:!?]$/, '');
        // 修复可能的URL格式问题
        url = url.replace(/qishuidouyincom/g, 'qishui.douyin.com');
        // 确保URL格式正确
        if (!url.startsWith('http')) {
            url = 'https://' + url;
        }
        return url;
    }
    return '';
}

// 修改输入框的粘贴事件处理
document.getElementById('musicUrl').addEventListener('paste', function(e) {
    // 获取粘贴的文本
    const pastedText = (e.clipboardData || window.clipboardData).getData('text');
    // 提取链接
    const extractedUrl = extractMusicUrl(pastedText);
    if (extractedUrl) {
        // 阻止默认粘贴行为
        e.preventDefault();
        // 设置提取后的链接
        this.value = extractedUrl;
        // 自动触发解析 (如果您不希望粘贴后立即解析,请注释掉此行)
        // parseMusic(); 
    }
});

// 修改输入框的输入事件处理
document.getElementById('musicUrl').addEventListener('input', function(e) {
    const text = this.value;
    // 如果输入框内容包含链接,自动提取
    if (text.includes('http') || text.includes('qishui')) {
        const extractedUrl = extractMusicUrl(text);
        if (extractedUrl && extractedUrl !== text) {
            this.value = extractedUrl;
        }
    }
});

// 修改调试信息显示函数
function updateDebugInfo(message, type = 'info') {
    const debugInfo = document.getElementById('debugInfo');
    const timestamp = new Date().toLocaleTimeString();
    const formattedMessage = `[${timestamp}] ${message}`;
    
    // 根据消息类型添加不同的样式类
    const messageElement = document.createElement('div');
    messageElement.textContent = formattedMessage;
    messageElement.className = type;
    
    debugInfo.appendChild(messageElement);
    debugInfo.scrollTop = debugInfo.scrollHeight;
}

// 修改解析函数
function parseMusic() {
    const musicUrl = document.getElementById('musicUrl').value.trim();
    if (!musicUrl) {
        layer.msg('请输入音乐分享链接', {icon: 2});
        return;
    }

    // 如果输入的不是纯链接,尝试提取
    if (!musicUrl.startsWith('http')) {
        const extractedUrl = extractMusicUrl(musicUrl);
        if (extractedUrl) {
            document.getElementById('musicUrl').value = extractedUrl;
        } else {
            layer.msg('无法识别有效的音乐分享链接', {icon: 2});
            return;
        }
    }
    
    // 清空上次解析结果
    document.getElementById('title').textContent = '';
    document.getElementById('downloadLink').href = '#';
    document.getElementById('downloadLink').download = '';
    document.getElementById('fileSize').textContent = '';
    document.getElementById('lyrics').innerHTML = '';

    // 清空调试信息
    document.getElementById('debugInfo').innerHTML = '';

    // 显示加载状态
    document.getElementById('result').style.display = 'none';
    document.getElementById('debug').style.display = 'block';
    updateDebugInfo('正在解析...', 'info');
    
    // 使用当前页面的完整URL
    const currentUrl = window.location.href;
    const requestUrl = `${currentUrl}${currentUrl.includes('?') ? '&' : '?'}ajax=1&url=${encodeURIComponent(musicUrl)}&type=json`;
    
    // 显示请求URL
    updateDebugInfo(`请求URL: ${requestUrl}`, 'info');
    
    fetch(requestUrl)
    .then(response => {
        // 显示响应状态
        updateDebugInfo(`响应状态: ${response.status} ${response.statusText}`, 'info');
        
        if (!response.ok) {
            return response.text().then(text => {
                throw new Error(`HTTP error! status: ${response.status}, response: ${text}`);
            });
        }
        return response.json();
    })
    .then(async data => {
        // 显示响应数据
        updateDebugInfo(`响应数据: ${JSON.stringify(data, null, 2)}`, 'info');
        
        if (data.code === 403) {
            throw new Error(data.msg);
        }
        
        if (data.code === 429) {
            // 处理请求限制
            const waitTime = data.wait_time || 60;
            const waitMinutes = Math.ceil(waitTime / 60);
            throw new Error(`请求过于频繁,请等待 ${waitMinutes} 分钟后再试`);
        }
        
        if (data.url) {
            document.getElementById('result').style.display = 'block';
            document.getElementById('title').textContent = data.name;
            
            try {
                // 获取代理URL
                const proxyUrl = `${window.location.href.split('?')[0]}?proxy=1&url=${encodeURIComponent(data.url)}`;
                
                // 显示加载状态
                updateDebugInfo('正在获取文件信息...', 'info');
                
                // 设置下载链接
                const downloadLink = document.getElementById('downloadLink');
                downloadLink.href = proxyUrl;
                downloadLink.download = `${data.name || 'music'}.m4a`;
                
                // 获取文件大小
                const { size } = await fetchAudio(proxyUrl);
                
                // 显示文件大小
                const fileSizeElement = document.getElementById('fileSize');
                fileSizeElement.textContent = `(${formatFileSize(size)})`;
                
                // 处理歌词
                const lyricsDiv = document.getElementById('lyrics');
                if (data.lyrics) {
                    lyricsDiv.innerHTML = data.lyrics.split('\n').map(line => 
                        `<div>${line}</div>`
                    ).join('');
                } else {
                    lyricsDiv.innerHTML = '<div class="no-lyrics">暂无歌词</div>';
                }
                
                // 更新积分显示
                getCurrentPoints();
                
                updateDebugInfo('解析完成', 'success');
            } catch (error) {
                console.error('Error:', error);
                updateDebugInfo(`错误: ${error.message}`, 'error');
                layer.msg('获取文件信息失败,请重试', {icon: 2});
            }
        } else {
            throw new Error(data.msg || '解析失败,未找到音乐URL');
        }
    })
    .catch(error => {
        console.error('Error:', error);
        updateDebugInfo(`错误: ${error.message}`, 'error');
        if (error.message.includes('积分不足') || error.message.includes('请先登录')) {
            layer.msg(error.message, {icon: 2});
        } else if (error.message.includes('请求过于频繁')) {
            layer.msg(error.message, {icon: 2, time: 5000});
        } else {
            layer.msg('解析出错,请查看调试信息', {icon: 2});
        }
    });
}
</script>

<?php
get_footer(); 
?>

 

© 版权声明
评论 抢沙发
头像
欢迎您留下宝贵的见解!
提交
头像

昵称

取消
昵称表情代码图片快捷回复

    暂无评论内容